home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cnstrnts / thinglab.lha / ThingLabII / SIGGRAPH_Demo / Minstrel.changes next >
Text File  |  1991-08-30  |  544KB  |  17,110 lines

  1. 'From Smalltalk-80, Version 2.3 of 13 June 1988 on 28 June 1991 at 10:28:28 pm'!
  2.  
  3.  
  4.  
  5. !Object methodsFor: 'Minstrel'!
  6. isGlyph
  7.     "No, I am not a glyph."
  8.  
  9.     ^false!
  10. warning: comment
  11.     "I leave notes to myself this way. This is a noop."! !
  12.  
  13. PaletteController comment:
  14. 'I am a controller for PaletteView.'!
  15.  
  16. !PaletteController methodsFor: 'controller handling'!
  17. controlActivity
  18.     "Handle mouse activities."
  19.  
  20.     | note mode |
  21.     "we deal only with red button activity"
  22.     (Sensor redButtonPressed)
  23.         ifTrue: [view buttons do: [: b | b respond]]
  24.         ifFalse: [^super controlActivity]!
  25. isControlActive
  26.     "Should we handle this mouse event?"
  27.  
  28.     ^super isControlActive & sensor blueButtonPressed not! !
  29.  
  30. SpecialSystemController comment:
  31. 'I allow the user to get the view (yellow-button) menu and the application (blue-button) menu using the red (mouse) button in the title bar of a SpecialSystemView. If the mouse is in the title itself, the application menu is invoked. If the mouse is in the gray area to either side of the title, then the view menu is invoked.'!
  32.  
  33. !SpecialSystemController methodsFor: 'menu messages'!
  34. blueButtonActivity
  35.     "Use special menu if collapsed. Otherwise, use my custom blueButtonMenu, which omits 'collapse'."
  36.  
  37.     | selector i |
  38.     view isCollapsed
  39.         ifTrue: [^super blueButtonActivity].
  40.  
  41.     (BlueButtonMenu isNil) ifTrue:
  42.         [BlueButtonMenu _ ActionMenu
  43.             labels: ' under \ move \ frame \ close ' withCRs
  44.             lines: #(3)
  45.             selectors: #(under move frame close)].
  46.     i _ BlueButtonMenu startUp.
  47.     (i > 0) ifTrue: [self perform: (BlueButtonMenu selectorAt: i)].!
  48. controlActivity
  49.  
  50.     (sensor blueButtonPressed and: [self viewHasCursor])
  51.         ifTrue: [^self blueButtonActivity].
  52.     (sensor redButtonPressed and:
  53.       [view labelDisplayBox containsPoint: sensor cursorPoint])
  54.         ifTrue: [^self redButtonActivity].
  55.     self controlToNextLevel.!
  56. redButtonActivity
  57.     "Give access to menus when the mouse (red button) goes down in the label part of my view. If the mouse is in the text box, act as though the yellow button were pressed (the application menu, by convention) otherwise, act as though the blue button were pressed (the view menu, by convention)."
  58.  
  59.     | p |
  60.     p _ sensor cursorPoint.
  61.     (view labelDisplayBox containsPoint: p)
  62.         ifTrue:
  63.             [((view labelTextDisplayBox containsPoint: p) and:
  64.                [view firstSubView notNil])
  65.                 ifTrue:
  66.                     [(view firstSubView controller respondsTo: #menuActivity) ifTrue:
  67.                         [view firstSubView controller menuActivity].
  68.                       (view firstSubView controller respondsTo: #yellowButtonActivity) ifTrue:
  69.                         [view firstSubView controller yellowButtonActivity]]
  70.                 ifFalse: [self blueButtonActivity]]
  71.         ifFalse: [].! !
  72.  
  73. !ParagraphEditor methodsFor: 'menu messages'!
  74. formEdit
  75.     "Evaluate the current text selection as an expression. If the result is a Form, open a bit editor on it. Otherwise, flash my view."
  76.  
  77.     | scaleFactor form |
  78.     scaleFactor _ 6@6.
  79.     self controlTerminate.
  80.     form _ Compiler new
  81.         evaluate: self selection asString
  82.         in: nil to: nil notifying: nil
  83.         ifFail: [^self controlInitialize].
  84.     (form isMemberOf: Form) ifFalse: [^view flash].
  85.     BitEditor openOnForm: form
  86.         at: (BitEditor locateMagnifiedView: form scale: scaleFactor) topLeft
  87.         scale: scaleFactor.! !
  88.  
  89. !ParagraphEditor methodsFor: 'editing'!
  90. readKeyboard
  91.  
  92.     | typeAhead currentCharacter |
  93.     OldUndoSelection _ UndoSelection.
  94.     self deselect.
  95.     typeAhead _ WriteStream on: (String new: 128).
  96.     beginTypeInBlock == nil
  97.         ifTrue: 
  98.             [UndoSelection _ self selection.
  99.             beginTypeInBlock _ startBlock copy].
  100.     [sensor keyboardPressed]
  101.         whileTrue: 
  102.             [CurrentEvent _ sensor keyboardEvent.
  103.             currentCharacter _ CurrentEvent keyCharacter.
  104.             (self perform: (Keyboard at: currentCharacter asciiValue + 1)
  105.                  with: typeAhead with: currentCharacter)
  106.                 ifTrue: [^self]].
  107.     self replaceSelectionWith:
  108.         (Text string: typeAhead contents emphasis: emphasisHere).
  109.     startBlock _ stopBlock copy.
  110.     self selectAndScroll! !
  111.  
  112. !ParagraphEditor methodsFor: 'keyboard shortcuts'!
  113. accept: characterStream key: aChar
  114.     "Save the current text of the text being edited as the current acceptable version for purposes of canceling."
  115.  
  116.     self accept.
  117.     ^true!
  118. again: characterStream key: aChar
  119.     "Redo the last find or replace operation."
  120.  
  121.     UndoSelection _ OldUndoSelection.
  122.     self again.
  123.     ^true!
  124. cancel: characterStream key: aChar
  125.     "Restore the text of the paragraph to be the text saved since initialization or the last accept."
  126.  
  127.     self cancel.
  128.     ^true!
  129. closeWindow: characterStream key: aChar 
  130.     "Close this window as if the 'close' blueButtonMenu item had been selected."
  131.  
  132.     model changeRequest  "check for changes in progress"
  133.         ifFalse: [^true].
  134.     self controlTerminate.
  135.     view topView controller close.
  136.     ^true!
  137. copy: characterStream key: aChar
  138.     "Copy the current text selection."
  139.  
  140.     self deselect.
  141.     self copySelection.
  142.     self select.
  143.     ^true!
  144. cut: characterStream key: aChar
  145.     "Cut the current text selection to the paste buffer."
  146.  
  147.     self cut.
  148.     ^true!
  149. format: stream key: code
  150.   (self respondsTo: #format) ifTrue: [
  151.     self closeTypeIn; format
  152.     ]
  153.   ifFalse: [
  154.     view flash
  155.     ].
  156.   ^true!
  157. paste: characterStream key: aChar
  158.     "Replace the current text selection by the text in the paste buffer."
  159.  
  160.     UndoSelection _ OldUndoSelection.
  161.     self paste.
  162.     ^true!
  163. undo: characterStream key: aChar
  164.     "Reset the state of the paragraph prior to the previous cut or paste edit."
  165.  
  166.     UndoSelection _ OldUndoSelection.
  167.     self undo.
  168.     ^true! !
  169.  
  170. !ParagraphEditor methodsFor: 'bjs functions'!
  171. doIt: stream key: code
  172.   (self respondsTo: #doIt) ifTrue: [
  173.     self closeTypeIn; doIt
  174.     ]
  175.   ifFalse: [
  176.     view flash
  177.     ].
  178.   ^true!
  179. fileOutBJSFunctions
  180.   "ParagraphEditor basicNew fileOutBJSFunctions"
  181.   | x |
  182.   x _ FileStream newFileNamed: 'bjsParagraphFunctions.st'.
  183.   ParagraphEditor fileOutCategory: 'bjs functions' asSymbol
  184.       on: x moveSource: false toFile: 0.
  185.   x nextChunkPut: 'ParagraphEditor basicNew installBJSfunctions'.
  186.   x close!
  187. inspectIt: stream key: code
  188.   (self respondsTo: #inspectIt) ifTrue: [
  189.     self closeTypeIn; inspectIt
  190.     ]
  191.   ifFalse: [
  192.     view flash
  193.     ].
  194.   ^true!
  195. installBJSfunctions
  196.   "ParagraphEditor basicNew installBJSfunctions"
  197.   "This mapping is for the Macintosh keyboard"
  198.  
  199. Keyboard
  200.    at: 29 put: #prevChar:key:;
  201.    at: 30 put: #nextChar:key:;
  202.    at: 31 put: #prevLine:key:;
  203.    at: 32 put: #nextLine:key:;
  204.  
  205.    at: 16r92 put: #undo:key:;  "F1"
  206.    at: 16r93 put: #cut:key:;    "F2"
  207.    at: 16r94 put: #copy:key:;  "F3"
  208.    at: 16r95 put: #paste:key:; "F4"
  209.  
  210.    at: 16r96 put: #accept:key:;  "F5"
  211.    at: 16r97 put: #cancel:key:;   "F6"
  212.  
  213.    at: 16r9A put: #doIt:key:;  "F9"
  214.    at: 16r9B put: #printIt:key:; "F10"
  215.    at: 16r9C put: #inspectIt:key: "F11"!
  216. nextChar: characterStream key: aChar
  217.   "Jump typing cursor over a close-bracket character"
  218.   | stopIndex block |
  219.    stopBlock character isNil ifTrue: [ "handle nil character after cuts"
  220.       stopBlock _ paragraph characterBlockForIndex: stopBlock stringIndex
  221.       ].
  222.   stopBlock character notNil ifTrue: [
  223.     stopIndex _ stopBlock stringIndex.
  224.     self deselect.
  225.     block _ paragraph characterBlockForIndex: stopIndex+1.
  226.     block topLeft > stopBlock topLeft ifTrue: [ "check for scrolling"
  227.       block topLeft y + paragraph textStyle baseline >
  228.         paragraph height ifTrue: [
  229.         paragraph scrollBy: paragraph textStyle lineGrid.
  230.         startBlock _ paragraph characterBlockForIndex: startBlock stringIndex.
  231.         stopBlock _ paragraph characterBlockForIndex: stopBlock stringIndex.
  232.         block _ paragraph characterBlockForIndex: block stringIndex.
  233.         self updateMarker
  234.         ]
  235.       ].
  236.     sensor leftShiftDown ifTrue: [
  237.       stopBlock _ block.
  238.       ]
  239.     ifFalse: [
  240.       startBlock _ stopBlock _ block.
  241.       ].
  242.     beginTypeInBlock _ startBlock copy.
  243.     self select
  244.     ]
  245.   ifFalse: [
  246.     self select
  247.     ].
  248.   self setEmphasisHere.
  249.   ^ true!
  250. nextLine: characterStream key: aChar
  251.   " "
  252.   |  block |
  253.   self deselect.
  254.   (stopBlock bottomLeft y + paragraph textStyle lineGrid) >
  255.     paragraph compositionRectangle corner y     ifTrue: [
  256.     paragraph scrollBy: paragraph textStyle lineGrid.
  257.     startBlock _ paragraph characterBlockForIndex: startBlock stringIndex.
  258.     stopBlock _ paragraph characterBlockForIndex: stopBlock stringIndex.
  259.     self updateMarker
  260.     ].
  261.   block _ paragraph characterBlockAtPoint: stopBlock topLeft +
  262.       (0 @ (paragraph textStyle lineGrid + 1)).
  263.   sensor leftShiftDown ifTrue: [
  264.     stopBlock _ block
  265.     ]
  266.   ifFalse: [
  267.     stopBlock _ startBlock _ block
  268.     ].
  269.   beginTypeInBlock _ startBlock copy.
  270.   self select.
  271.   self setEmphasisHere.
  272.   ^true!
  273. prevChar: characterStream key: aChar
  274.   "Jump typing cursor over a close-bracket character"
  275.   | startIndex block |
  276.   startBlock stringIndex > 1 ifTrue:    [
  277.     startIndex _ startBlock stringIndex.
  278.     self deselect.
  279.     block _ paragraph characterBlockForIndex: startIndex-1.
  280.     block topLeft y < startBlock topLeft y ifTrue: [ "check for scrolling"
  281.       block topLeft y < paragraph compositionRectangle origin y ifTrue: [
  282.         paragraph scrollBy: paragraph textStyle lineGrid negated.
  283.         startBlock _ paragraph characterBlockForIndex: startBlock stringIndex.
  284.         stopBlock _ paragraph characterBlockForIndex: stopBlock stringIndex.
  285.         block _ paragraph characterBlockForIndex: block stringIndex.
  286.         self updateMarker
  287.       ]  ].
  288.     sensor leftShiftDown ifTrue: [
  289.       startBlock _ block
  290.       ]
  291.     ifFalse: [
  292.       startBlock _ stopBlock _ block.
  293.       ].
  294.     beginTypeInBlock _ startBlock copy.
  295.     self select
  296.     ]
  297.   ifFalse:  [
  298.     self select
  299.     ].
  300.   self setEmphasisHere.
  301.   ^ true!
  302. prevLine: characterStream key: aChar
  303.   " "
  304. |  block |
  305. self deselect.
  306. (startBlock topLeft y - paragraph textStyle lineGrid) <
  307.     paragraph compositionRectangle origin y      ifTrue: [
  308.   paragraph scrollBy: paragraph textStyle lineGrid negated.
  309.   startBlock _ paragraph characterBlockForIndex: startBlock stringIndex.
  310.   stopBlock _ paragraph characterBlockForIndex: stopBlock stringIndex.
  311.   self updateMarker
  312.   ].
  313. block _ paragraph characterBlockAtPoint: startBlock topLeft -
  314.     (0 @ (paragraph textStyle lineGrid - 1)).
  315. sensor leftShiftDown ifTrue: [
  316.   startBlock _ block
  317.   ]
  318. ifFalse: [
  319.   startBlock _ stopBlock _ block
  320.   ].
  321. beginTypeInBlock _ startBlock copy.
  322. self select.
  323. self setEmphasisHere.
  324. ^true!
  325. printIt: stream key: code
  326.   (self respondsTo: #printIt) ifTrue: [
  327.     self closeTypeIn; printIt
  328.     ]
  329.   ifFalse: [
  330.     view flash
  331.     ].
  332.   ^true!
  333. processRedButton
  334.     "The user pressed a red mouse button, meaning create a new text selection.
  335.     Highlighting the selection is carried out by the paragraph itself.  Double
  336.     clicking causes a selection of the area between the nearest enclosing
  337.     delimitors;  extension is based on both ends if different."
  338.  
  339.     | selectionBlocks block1 block2 |
  340.     self deselect.
  341.     self closeTypeIn.
  342.     selectionBlocks _ paragraph mouseSelect: startBlock to: stopBlock.
  343.     selectionShowing _ true.
  344.     sensor leftShiftDown ifTrue: [
  345.         block1 _ selectionBlocks at: 1.
  346.         block2 _ selectionBlocks at: 2.
  347.         block1 = block2 ifTrue: [
  348.             paragraph displayCaretForBlock: block1.
  349.             block1 <= startBlock ifTrue: [ startBlock _ block1 ]
  350.             ifFalse: [ stopBlock _ block1 ].
  351.             ]
  352.         ifFalse: [
  353.             paragraph reverseFrom: block1 to: block2.
  354.             block1 < startBlock ifTrue: [ startBlock _ block1 ].
  355.             block2 > stopBlock ifTrue: [ stopBlock _ block2 ]
  356.             ].
  357.         paragraph reverseFrom: startBlock to: stopBlock.
  358.         selectionShowing _ true.
  359.         ]
  360.     ifFalse: [
  361.         startBlock _ selectionBlocks at: 1.
  362.         stopBlock _ selectionBlocks at: 2
  363.         ].
  364.     self updateMarker.
  365.     self setEmphasisHere! !
  366.  
  367. !TextController methodsFor: 'menu messages'!
  368. localMenuItem: selector
  369.     ^ #(cut paste copySelection again undo cancel accept formEdit) includes: selector! !
  370.  
  371. PianoRollController comment:
  372. 'I am a controller for PianoRollView.'!
  373.  
  374. !PianoRollController methodsFor: 'initialize'!
  375. initialize
  376.     "Set up my yellow button menu."
  377.  
  378.     | myMenu myMenuMessages |
  379.     myMenu _ PopUpMenu labels:
  380. 'Play All
  381. Play Window
  382. Play Selected Notes
  383. Play Time Range
  384. Clear Selection
  385. Voice -> Selection
  386. Selection -> Voice
  387. Delete Selection
  388. Record
  389. Set Rate
  390. Inspect Notes
  391. Show Voice Counts'
  392.     lines: #(4 5 7).
  393.  
  394.     myMenuMessages _
  395.         #(playAll
  396.            playWindow
  397.            playSelectedNotes
  398.            playTimeRange
  399.            clearSelection
  400.            addVoiceToSelection
  401.            moveSelectionToVoice
  402.            deleteSelection
  403.            record
  404.            setRate
  405.            inspectNotes
  406.            showVoiceCounts).
  407.  
  408.     super initialize.
  409.     self
  410.         yellowButtonMenu: myMenu
  411.         yellowButtonMessages: myMenuMessages.! !
  412.  
  413. !PianoRollController methodsFor: 'controller handling'!
  414. controlActivity
  415.     "Handle mouse activities."
  416.  
  417.     | note mode |
  418.     "we deal only with red button activity"
  419.     (Sensor redButtonPressed)
  420.         ifFalse: [^super controlActivity].
  421.  
  422.     "drag a time selection marker"
  423.     (view selectionBar containsPoint: self viewCursorPoint)
  424.         ifTrue: [view dragTimeMarker. ^self].
  425.  
  426.     "find the note pointed to, if any"
  427.     note _ view nearestNote: self viewCursorPoint.
  428.  
  429.     "if the note pointed to was already in the selection, use remove mode; otherwise, use add mode"
  430.     ((note notNil) and: [view selected includes: note])
  431.         ifTrue:
  432.             [mode _ #removing.
  433.              view removeFromSelection: note]
  434.         ifFalse:
  435.             [mode _ #adding.
  436.              (note notNil) ifTrue:
  437.                 [view addToSelection: note]].
  438.  
  439.     [Sensor redButtonPressed]
  440.         whileTrue:
  441.             [note _ view nearestNote: self viewCursorPoint.
  442.              (note notNil) ifTrue:
  443.                 [(mode == #adding)
  444.                     ifTrue: [view addToSelection: note]
  445.                     ifFalse: [view removeFromSelection: note]]].!
  446. isControlActive
  447.     "Should we handle this mouse event?"
  448.  
  449.     ^super isControlActive & sensor blueButtonPressed not!
  450. viewCursorPoint
  451.     "Answer the current cursor point in view coordinates."
  452.  
  453.     ^sensor cursorPoint - view insetDisplayBox origin! !
  454.  
  455. !PianoRollController methodsFor: 'menu messages'!
  456. addVoiceToSelection
  457.     "Prompts for a voice number and adds the notes of that voice to the selection."
  458.  
  459.     | voice empty |
  460.     voice _ (FillInTheBlank request: 'Voice?') asNumber.
  461.     empty _ true.
  462.     model do:
  463.         [: note |
  464.             (note voice = voice)
  465.                 ifTrue: [empty _ false. view addToSelection: note]].
  466.     empty
  467.         ifTrue: [self notify: 'No notes in that voice'].!
  468. clearSelection
  469.     "Clear the current selection."
  470.  
  471.     view clearSelection.!
  472. deleteSelection
  473.     "Delete selected notes after asking for confirmation."
  474.  
  475.     BinaryChoice
  476.         message: 'Delete all selected notes?' 
  477.         displayAt: Sensor cursorPoint 
  478.         ifTrue:
  479.             [view selected do: [: note | model remove: note].
  480.              view cacheUpdate.
  481.              view clearSelection].!
  482. inspectNotes
  483.     "Bring up an inspector on the selected note or notes."
  484.  
  485.     | selectedNotes |
  486.  
  487.     selectedNotes _ view selected asSortedCollection.
  488.     selectedNotes isEmpty ifTrue: [^self].                "nothing selected"
  489.     selectedNotes size > 1
  490.         ifTrue: [selectedNotes inspect]                    "multiple notes selected"
  491.         ifFalse: [(selectedNotes at: 1) inspect].            "single note selected"!
  492. moveSelectionToVoice
  493.     "Prompts for a voice number and adds all selected notes to that voice."
  494.  
  495.     | voice |
  496.  
  497.     voice _
  498.         (FillInTheBlank
  499.             request: 'Move selected notes to which voice?') asNumber.
  500.  
  501.     voice == 0 ifTrue: [^self].
  502.  
  503.     view selected do:
  504.         [: note | (note voice: voice)].!
  505. playAll
  506.     "Perform the entire score."
  507.  
  508.     Cursor execute showWhile:
  509.         [self playFrom: 0 to: model scoreTime].!
  510. playFrom: startTime to: endTime
  511.     "Perform the score between the given times."
  512.  
  513.     | startIndex endIndex tempScore voiceMap |
  514.     startIndex _ (model indexAfter: startTime).
  515.     endIndex _ (model indexBefore: endTime).
  516.     (startIndex <= endIndex) ifFalse: [^self].
  517.     tempScore _ model copyFrom: startIndex to: endIndex.
  518.     voiceMap _ view voiceMap.
  519.     tempScore _ tempScore select: [: note | voiceMap at: note voice].
  520.     (tempScore isEmpty) ifTrue: [^self].
  521.     tempScore playFrom: (tempScore first time) rate: view rate / 100.0.!
  522. playSelectedNotes
  523.  
  524.     | score |
  525.     Cursor execute showWhile:
  526.         [score _ Score new.
  527.          score addAll: (view selected asSortedCollection).
  528.          score isEmpty ifTrue: [^self].
  529.          score playFrom: (score first time) rate: view rate / 100.0].!
  530. playTimeRange
  531.     "Play the notes within the selected time range."
  532.  
  533.     Cursor execute showWhile:
  534.         [self playFrom: view timeRangeStart to: view timeRangeEnd].!
  535. playWindow
  536.     "Play just the notes in the visible window."
  537.  
  538.     Cursor execute showWhile:
  539.         [self playFrom: view startVisibleSpan to: view endVisibleSpan].!
  540. record
  541.  
  542.     | selectedNotes scoreToPlay startTime newNotes |
  543.     self notify: 'Proceed to record into voice 17'.
  544.     selectedNotes _ view selected.
  545.     (selectedNotes isEmpty)
  546.         ifTrue:
  547.             [scoreToPlay _ model.
  548.              startTime _ 0]
  549.         ifFalse:
  550.             [scoreToPlay _ (Score new: selectedNotes size) addAll: selectedNotes asSortedCollection; yourself.
  551.              startTime _ scoreToPlay first time].
  552.  
  553.     newNotes _ (MidiRecorder new) overDub: scoreToPlay playFrom: startTime rate: view rate / 100.0.
  554.     newNotes do: [: note | note voice: 17. note time: (note time + startTime)].
  555.     model _ model mergedWith: newNotes.
  556.  
  557.     view model: model.
  558.     view cacheUpdate.
  559.     view displayView.!
  560. setRate
  561.  
  562.     | newRate |
  563.     newRate _
  564.         (FillInTheBlank
  565.             request: 'Type the performance rate in percent followed by a CR'
  566.             initialAnswer: view rate printString) asNumber.
  567.     newRate > 0 ifTrue: [view rate: newRate].!
  568. showVoiceCounts
  569.  
  570.     | tallys out |
  571.     tallys _ Bag new.
  572.     model do:
  573.         [: scoreElement |
  574.             (scoreElement isNote)
  575.                 ifTrue: [tallys add: scoreElement voice]].
  576.     out _ OrderedCollection new.
  577.     (tallys sortedElements) do:
  578.         [: assoc |
  579.             out addLast:
  580.                 'Voice ', assoc key printString, ': ',
  581.                 assoc value printString].    
  582.     out inspect.! !
  583.  
  584. !PianoRollController methodsFor: 'scrolling'!
  585. computeMarkerRegion
  586.     "Answer a rectangle for the marker region of the scroll bar. This rectangle should have an orgin of 0@0, a width of 10, and a height that is proportional to the percentage of the full score that is currently visible."
  587.  
  588.     | length |
  589.     length _ (self percentVisible * scrollBar inside height) rounded.
  590.     ^0@0 extent: 10@length!
  591. markerDelta
  592.     "Answer how much to move the marker by by."
  593.  
  594.     ^(marker top - scrollBar inside top) -
  595.         (self percentPosition * scrollBar inside height) rounded!
  596. percentPosition
  597.     "Answer how far through the score we are (a number between zero and one)."
  598.  
  599.     ^view timeOffset / (model scoreTime max: 1)!
  600. percentVisible
  601.     "Answer the fraction of the score that is visible."
  602.  
  603.     ^view visibleSpan / (model scoreTime max: 1)!
  604. scrollAbsolute
  605.     "Re-implementation of superclass method to avoid flashing when the thumb hasn't been moved."
  606.  
  607.     | oldMarker lastY y |
  608.     self changeCursor: Cursor marker.
  609.     sensor anyButtonPressed ifFalse: [^self].
  610.     lastY _ -10.
  611.     [sensor anyButtonPressed] whileTrue:
  612.         [y _ sensor cursorPoint y.
  613.          (y ~= lastY) ifTrue:
  614.             [oldMarker _ marker.
  615.              marker _ marker translateBy:
  616.                 0@(((y - marker center y)
  617.                     min: scrollBar inside bottom - marker bottom)
  618.                     max: scrollBar inside top - marker top).
  619.             (oldMarker areasOutside: marker), (marker areasOutside: oldMarker) do:
  620.                 [:region | Display fill: region rule: Form reverse mask: Form gray].
  621.             self scrollView.
  622.             lastY _ y]].
  623.     scrollBar display.
  624.     self moveMarker.!
  625. scrollAmount
  626.     "The amount to scroll is proportional to the vertical distance from the top of the scroll bar to the cursor."
  627.  
  628.     ^((sensor cursorPoint y - scrollBar inside top) * view visibleSpan) // scrollBar inside height!
  629. scrollView
  630.     "Absolute scrolling: the user is thumbing."
  631.  
  632.     | percent scorePosition |
  633.     percent _ (sensor cursorPoint y - scrollBar inside top) / scrollBar inside height.
  634.     percent _ (percent min: 1.0) max: 0.0.
  635.     scorePosition _ (percent * model scoreTime) truncated.
  636.     (model scoreTime ~= scorePosition) ifTrue:
  637.         [view scrollTo: scorePosition].!
  638. scrollView: delta
  639.     "Relative scrolling by the given amount."
  640.  
  641.     view scrollTo: view timeOffset - delta.! !
  642.  
  643. !BitEditor methodsFor: 'menu messages'!
  644. storeToPaste
  645.  
  646.     | s |
  647.     s _ WriteStream on: (String new).
  648.     (view workingForm) storeOn: s base: 10.
  649.     ParagraphEditor storePasteText: (s contents).
  650.     view topView controller close.! !
  651.  
  652. !BitEditor methodsFor: 'private'!
  653. initializeYellowButtonMenu
  654.  
  655.     self
  656.         yellowButtonMenu: (PopUpMenu labels:
  657.             'accept\cancel\store to paste' withCRs)
  658.         yellowButtonMessages: #(accept cancel storeToPaste)! !
  659.  
  660. GestureController comment:
  661. 'I supports simple click and drag gestures, using the passage of real time to determine the difference between a click, double-click, or drag.'!
  662.  
  663. !GestureController methodsFor: 'control defaults'!
  664. controlActivity
  665.     "Process user activity. This consists of either red button gestures or yellow button menu activity. Any other activity is handled by my superclass. Examples of gestures are: click, double-click, drag, and sweep (a special kind of drag). See the 'gestures' category for the full list."
  666.  
  667.     (sensor yellowButtonPressed) ifTrue: [^self menuActivity].
  668.     (sensor redButtonPressed) ifTrue: [^self possibleClickAt: sensor cursorPoint].
  669.     super controlActivity.!
  670. isControlActive
  671.     "Let the super view handle blue button activity."
  672.  
  673.     ^self viewHasCursor & sensor blueButtonPressed not!
  674. isControlWanted
  675.  
  676.     ^self viewHasCursor & sensor blueButtonPressed not! !
  677.  
  678. !GestureController methodsFor: 'gestures'!
  679. clickAt: aPoint
  680.     "Perform action for a red button click at the given point. The default is to do vanilla red button activity."
  681.  
  682.     self redButtonActivity.!
  683. doubleClickAt: aPoint
  684.     "Perform action for a red button double-click at the given point. The default is to do vanilla red button activity."
  685.  
  686.     self redButtonActivity.!
  687. dragAt: aPoint
  688.     "Perform action for a red button drag starting at the given point. The default is to do vanilla red button activity."
  689.  
  690.     self redButtonActivity.!
  691. redButtonActivity
  692.     "If the subclass does not override a gesture messages, it is sent this message to perform vanilla red button activity. This default method does nothing."!
  693. sweepAt: aPoint
  694.     "Perform action for a red button sweep starting at the given point. (A sweep is a diagonal down-and-right drag, used by some applications to sweep out an area for group selection.) The default is to do vanilla red button activity."
  695.  
  696.     self redButtonActivity.! !
  697.  
  698. !GestureController methodsFor: 'menu handling'!
  699. menuActivity
  700.     "If the yellow button is pressed, this message is sent to the controller to handle the application menu. It is up to subclasses to override this message. This default method does nothing."! !
  701.  
  702. !GestureController methodsFor: 'private-timer'!
  703. resetTimer
  704.     "Reset our timer by remembering the current value of the millisecond clock."
  705.  
  706.     startTime _ Time millisecondClockValue.!
  707. timeOut: timeOutInMilliseconds
  708.     "Compute the timer value by subtracting the time at which the timer was last reset from the current millisecond clock value. Answer true if the result is greater than timeOutInMilliseconds."
  709.  
  710.     | timerVal |
  711.     timerVal _ Time millisecondClockValue - startTime.
  712.     ^(timerVal > timeOutInMilliseconds)! !
  713.  
  714. !GestureController methodsFor: 'private-gestures'!
  715. dragOrSweepAt: aPoint
  716.     "The button was held down too long for it to be a click so it is either a drag or a sweep. It is considered a sweep if the mouse has moved in definite downward-and-right manner between the time the button was depressed and now. (Note that the constants in this method may need to be changed if the timeout in possibleClickAt: is changed.)"
  717.  
  718.     | delta |
  719.     delta _ sensor cursorPoint - aPoint.
  720.     ((delta x > 1) | (delta y > 1))
  721.         ifTrue: [self sweepAt: aPoint]
  722.         ifFalse: [self dragAt: aPoint].!
  723. possibleClickAt: aPoint
  724.     "Invoked when the red button is first depressed. If the button is released before the timeout period has elapsed, then there is at least one click and we must look for a second click. Otherwise, the gesture is a drag or sweep." 
  725.  
  726.     self resetTimer.
  727.     [(self timeOut: 150) not & sensor redButtonPressed]
  728.         whileTrue: ["wait for timeout or button up"].
  729.     (sensor redButtonPressed not)    "has the button gone up?"
  730.         ifTrue: [self possibleDoubleClickAt: aPoint]
  731.         ifFalse: [self dragOrSweepAt: aPoint].!
  732. possibleDoubleClickAt: aPoint
  733.     "Invoked after the first click (i.e. the button is up). If the button is depressed again before the timeout period has elapsed, then the gesture is a double click. Otherwise, the gesture is a single click. A single click is recorded immediately. Thus, a double click causes the sequence of messages: 'clickAt:' and 'doubleClickAt:' to be sent."
  734.  
  735.     self resetTimer.
  736.     [(self timeOut: 190) not & sensor redButtonPressed not]
  737.         whileTrue: ["wait for timeout or button down"].
  738.     (sensor redButtonPressed)    "has the button gone down?"
  739.         ifTrue: [self doubleClickAt: aPoint]
  740.         ifFalse: [self clickAt: aPoint].! !
  741.  
  742. SceneController comment:
  743. 'I am a controller for SceneViews. I support gestures for scrolling, click-selection, and area selection of scene glyphs. I also support construction operations such as inserting new glyphs and merging glyphs to make them share a common point.'!
  744.  
  745. !SceneController methodsFor: 'initialize-release'!
  746. initialize
  747.  
  748.     super initialize.
  749.     myMenu _ CustomMenu new.
  750.     lastMenuItem _ nil.
  751.     running _ true.
  752.     lastPartsMenuString _ ''.
  753.     partsMenuCache _ nil.! !
  754.  
  755. !SceneController methodsFor: 'control defaults'!
  756. controlActivity
  757.     "Process user mouse and keyboard activity."
  758.  
  759.     (sensor keyboardPressed) ifTrue: [^self readKeyboard].
  760.     (sensor yellowButtonPressed) ifTrue: [^self menuActivity].
  761.  
  762.     "The following code allows click, drag, and sweep gestures even in 'operate' mode:"
  763.     (sensor redButtonPressed) ifTrue: [^self possibleClickAt: sensor cursorPoint].
  764.  
  765.     "Note: replace the previous code with the following to disable click, drag, and sweep gestures in 'operate' mode. This is good for naive users and quick response."
  766.     "(sensor redButtonPressed) ifTrue:
  767.         [(running)
  768.             ifTrue: [^self processMouseAt: sensor cursorPoint]
  769.             ifFalse: [^self possibleClickAt: sensor cursorPoint]]."
  770.  
  771.     "model backgroundTask: view."
  772.     thePlan notNil
  773.         ifTrue: 
  774.             [thePlan execute.
  775.             view displayFeedback]!
  776. controlInitialize
  777.     super controlInitialize.
  778.     model isAnimated
  779.         ifTrue: [thePlan isNil
  780.                 ifTrue: 
  781.                     [thePlan _ model computeBackgroundPlan.
  782.                     view computeBackground]]
  783.         ifFalse: [thePlan _ nil]! !
  784.  
  785. !SceneController methodsFor: 'gestures'!
  786. clickAt: aPoint
  787.     "If the mouse is clicked over a glyph that wants mouse input and we are in 'run' mode, pass the mouse to it. Otherwise, select the glyph under aPoint. If the shift key is depressed, the glyph's inclusion in the selection is toggled: that is, it is added to the selection if it is not currently selected and removed from the selection if it is currently selected."
  788.  
  789.     "first, try to process mouse input for the glyph at aPoint"
  790.     (self processMouseAt: aPoint) ifTrue: [^self].
  791.  
  792.     "if that fails, do select operation"
  793.     self selectAt: aPoint toggleFlag: (sensor leftShiftDown).
  794.     view displayScene.!
  795. doubleClickAt: aPoint
  796.     "Handle a double-click action by trying to inspect the glyph under aPoint. A double-click that is not over any glyph does a selectAll."
  797.  
  798.     | glyph |
  799.     glyph _ self glyphAt: aPoint.
  800.     (glyph notNil)
  801.         ifTrue:
  802.             [model clearSelection.
  803.              self selectAt: aPoint toggleFlag: false.
  804.              view displayScene.
  805.              self inspectGlyph]
  806.         ifFalse:
  807.             [self selectAll.
  808.              sensor waitNoButton].!
  809. dragAt: aPoint
  810.     "Handle a drag action. If aPoint is over a glyph that is interested in mouse actions, let that glyph handle the mouse. Otherwise, move or scroll depending on whether or not the given point is over a selectable glyph or not."
  811.  
  812.     | glyph |
  813.     "first, try to process mouse input for the glyph at aPoint"
  814.     (self processMouseAt: aPoint) ifTrue: [^self].
  815.  
  816.     "if that fails, handle the normal move-or-scroll situation"
  817.     glyph _ self glyphAt: aPoint.
  818.     (glyph notNil)
  819.         ifTrue:
  820.             ["if the glyph is not in the selection, select it"
  821.              (model selected includes: glyph) ifFalse:
  822.                 [self selectAt: aPoint toggleFlag: (sensor leftShiftDown)].
  823.              self moveAt: aPoint]
  824.         ifFalse: [self scrollAt: aPoint].!
  825. processMouseAt: aPoint
  826.     "If we are in 'run' mode and the given point is over a glyph that is interested in mouse actions, let that glyph handle the mouse and answer true. Otherwise, answer false."
  827.  
  828.     | mouseGlyph t |
  829.     running ifFalse: [^false].
  830.  
  831.     mouseGlyph _ self mouseGlyphAt: aPoint.
  832.     (mouseGlyph notNil)
  833.         ifTrue: [self passMouseTo: mouseGlyph. ^true]
  834.         ifFalse: [^false].!
  835. sweepAt: aPoint
  836.     "Handle a sweep gesture by doing an area-select. If the shift key is down, then toggle select all enclosed glyphs. Otherwise, clear the selection first. If there was a glyph under the mouse at the start of the sweep, consider it a drag (what a drag!!)."
  837.  
  838.     "first, try to process mouse input for the glyph at aPoint"
  839.     (self processMouseAt: aPoint) ifTrue: [^self].
  840.  
  841.     "if that fails, handle the normal move-or-area-select situation"
  842.     ((self glyphAt: aPoint) notNil)    "check for a drag situation"
  843.         ifTrue: [self dragAt: aPoint]
  844.         ifFalse:
  845.             [self
  846.                 selectAreaAt: aPoint
  847.                 toggleFlag: (sensor leftShiftDown)].! !
  848.  
  849. !SceneController methodsFor: 'menu handling'!
  850. addMenuItems: debugging
  851.     "Answer my yellow-button menu given the current selection and possibly some other view or controller state. The goal is to present in the menu only those possibilities which are legal commands at this juncture. If debugging is true, present a additional options which might be useful to implementors and other gurus."
  852.  
  853.     | argCount |
  854.     argCount _ model selected size.
  855.  
  856.     running
  857.         ifTrue: [myMenu add: ' edit ' action: #edit]
  858.         ifFalse: [myMenu add: ' operate ' action: #operate].
  859.     myMenu addLine.
  860.  
  861.     myMenu add: ' scroll ' action: #scroll.
  862.     myMenu add: ' area ' action: #selectArea.
  863.     myMenu addLine.
  864.     myMenu add: ' all ' action: #selectAll.
  865.     (model selected size > 0) ifTrue:
  866.         [myMenu add: ' none ' action: #clearSelection].
  867.     myMenu addLine.
  868.  
  869.     myMenu add: ' insert ' action: #insert.
  870.     (argCount > 0) ifTrue:
  871.         [myMenu add: ' delete ' action: #delete].
  872.     myMenu addLine.
  873.  
  874.     (argCount > 0) ifTrue:
  875.         [myMenu add: ' top ' action: #moveToFront.
  876.          myMenu add: ' bottom ' action: #moveToRear.
  877.          myMenu addLine].
  878.  
  879.     (argCount > 0) ifTrue:
  880.         [(argCount > 1) ifTrue:
  881.             [myMenu add: ' merge ' action: #merge].
  882.          myMenu add: ' unmerge ' action: #unmerge.
  883.          myMenu addLine].
  884.  
  885.     (argCount > 0) ifTrue:
  886.         [(argCount > 1) ifTrue:
  887.             [myMenu add: ' h-align ' action: #alignHorizontal.
  888.              myMenu add: ' v-align ' action: #alignVertical].
  889.          myMenu add: ' unalign ' action: #unalign.
  890.          myMenu addLine].
  891.  
  892.     (argCount > 0) ifTrue:
  893.         [(argCount = 2) ifTrue:
  894.             [myMenu add: ' equate ' action: #equate].
  895.          myMenu add: ' unequate ' action: #unequate.
  896.          myMenu addLine].
  897.  
  898.     (argCount = 1) ifTrue:
  899.         [myMenu add: ' attach button ' action: #attachButton.
  900.          myMenu add: ' attach menu ' action: #attachMenu.
  901.          myMenu add: ' remove button ' action: #removeButton.
  902.          myMenu add: ' remove menu ' action: #removeMenu.
  903.          myMenu addLine.
  904.          myMenu add: ' inspect ' action: #inspectGlyph.
  905.          myMenu addLine].!
  906. menuActivity
  907.     "Present the yellow button menu and determine which menu item, if any, the user selected. If an item was selected, then send that message to the object designated as the menu message receiver. Remember the menu item across menu invocations."
  908.  
  909.     | menu item |
  910.     menu _ self yellowButtonMenu: (sensor leftShiftDown).
  911.     (menu isNil) ifTrue: [^self].
  912.  
  913.     item _ menu invoke: lastMenuItem.
  914.     lastMenuItem _ item.
  915.     (item notNil) ifTrue: [self perform: item].!
  916. yellowButtonMenu: debugging
  917.     "Answer my yellow-button menu, constructed by sending myself the message 'addMenuItems: debugging.' Items are appended to the CustomMenu myMenu; this allows subclasses to augment the menu provided  by their superclass without the maintainance headache of copying the menu creation code into the subclass."
  918.  
  919.     myMenu _ CustomMenu new.
  920.     self addMenuItems: debugging.
  921.     ^myMenu! !
  922.  
  923. !SceneController methodsFor: 'menu operations'!
  924. alignHorizontal
  925.     "Constrain all selected glyphs have the y location of the left-most selected glyph."
  926.  
  927.     | args leftMost newY |
  928.     args _ model selected asOrderedCollection.
  929.     leftMost _ args first.
  930.     args do:
  931.         [: g |
  932.          (g locationPoints first x < leftMost locationPoints first x) ifTrue:
  933.             [leftMost _ g]].
  934.     args remove: leftMost.
  935.     newY _ leftMost locationPoints first y.
  936.     args do:
  937.         [: g |
  938.          LayoutConstraint
  939.             hAlign: (g locationPoints first)
  940.             with: (leftMost locationPoints first)].
  941.     leftMost locationPoints first y: newY.
  942.     view computeEnclosingRectangle.
  943.     view displayScene.!
  944. alignVertical
  945.     "Constrain all selected glyphs have the x location of the top-most selected glyph."
  946.  
  947.     | args topMost newX |
  948.     args _ model selected asOrderedCollection.
  949.     topMost _ args first.
  950.     args do:
  951.         [: g |
  952.          (g locationPoints first y < topMost locationPoints first y) ifTrue:
  953.             [topMost _ g]].
  954.     args remove: topMost.
  955.     newX _ topMost locationPoints first x.
  956.     args do:
  957.         [: g |
  958.          LayoutConstraint
  959.             vAlign: (g locationPoints first)
  960.             with: (topMost locationPoints first)].
  961.     topMost locationPoints first x: newX.
  962.     view computeEnclosingRectangle.
  963.     view displayScene.!
  964. clearSelection
  965.     "Unselect everything."
  966.  
  967.     model clearSelection.
  968.     view displayScene.!
  969. delete
  970.     "Delete all the selected glyphs and their parents."
  971.  
  972.     self deleteGlyphs: model selected.!
  973. edit
  974.  
  975.     running _ false.!
  976. equate
  977.     "Add a user-defined equality constraint between subparts of the two selected glyphs."
  978.  
  979.     | args first second firstPath secondPath |
  980.     args _ model selected asOrderedCollection.
  981.     (args first locationPoints first x < args last locationPoints first x)
  982.         ifTrue: [first _ args first. second _ args last]
  983.         ifFalse: [second _ args first. first _ args last].
  984.  
  985.     firstPath _ FillInTheBlank
  986.         request:
  987. 'Path for the subpart of interest in the left-hand glyph (', first printString, ').
  988. Use dot notation to specify the path (e.g. ''line1.p1.x'').'.
  989.     (firstPath size = 0) ifTrue: [^self].
  990.  
  991.     secondPath _ FillInTheBlank
  992.         request:
  993. 'Path for the subpart of interest in the right-hand glyph (', second printString, ').
  994. Use dot notation to specify the path (e.g. ''line1.p1.x'').'.
  995.     (secondPath size = 0) ifTrue: [^self].
  996.  
  997.     UserEqualityConstraint
  998.         var: (Constraint getVarAt: firstPath in: first)
  999.         var:  (Constraint getVarAt: secondPath in: second)
  1000.         strength: #strongPreferred.
  1001.     view computeEnclosingRectangle.
  1002.     view displayScene.!
  1003. insert
  1004.     "Prompt the user with a menu of glyph classes and add a new instance of the selected class."
  1005.  
  1006.     | className |
  1007.     className _ self partsMenu startUp.
  1008.     (className = 0) ifTrue: [^self].
  1009.     self addAndPlace: (Smalltalk at: className) new.!
  1010. inspectGlyph
  1011.     "If a single glyph is selected, inspect it."
  1012.  
  1013.     (self argument notNil) ifTrue:
  1014.         [self argument inspect].!
  1015. merge
  1016.     "Attempt the merge the selected glyphs together. The first glyph is the sink with which the remaining glyphs are merged."
  1017.  
  1018.     self mergeGlyphs: model selected asOrderedCollection.!
  1019. moveToFront
  1020.     "Move the currently selected glyphs to the front, in front of other glyphs."
  1021.  
  1022.     (model selected asOrderedCollection) do:
  1023.         [: glyph | model moveToFront: glyph].
  1024.     view displayScene.!
  1025. moveToRear
  1026.     "Move the currently selected glyphs to the rear, behind other glyphs."
  1027.  
  1028.     (model selected asOrderedCollection) do:
  1029.         [: glyph | model moveToRear: glyph].
  1030.     view displayScene.!
  1031. operate
  1032.  
  1033.     running _ true.!
  1034. scroll
  1035.     "Wait for the mouse button to be pressed, then scroll."
  1036.  
  1037.     Cursor hand showWhile: [sensor waitButton].
  1038.     self scrollAt: sensor cursorPoint.!
  1039. selectAll
  1040.     "Select all selectable glyphs."
  1041.  
  1042.     model clearSelection.
  1043.     model selectableGlyphsDo: [: g | model select: g].
  1044.     view displayScene.!
  1045. selectArea
  1046.     "Select everything in a rectangular area specified using the mouse. If the shift key is down, toggle select everything in the area."
  1047.  
  1048.     Cursor origin showWhile: [sensor waitButton].
  1049.     self selectAreaAt: (sensor cursorPoint) toggleFlag: (sensor leftShiftDown).!
  1050. unalign
  1051.     "Remove all alignment constraints from the selected glyphs."
  1052.  
  1053.     model selected do:
  1054.         [: glyph |
  1055.          glyph varsDo:
  1056.             [: var |
  1057.              var constraints copy do:
  1058.                  [: c |
  1059.                   (c isLayoutConstraint) ifTrue:
  1060.                     [c destroyConstraint]]]].!
  1061. unequate
  1062.     "Remove all user-added equality constraints between the selected glyphs. If exactly two glyphs are selected, then the interesection of their set of user-added constraints is removed."
  1063.  
  1064.     | selected equalitiesOnFirst |
  1065.     selected _ model selected asOrderedCollection.
  1066.     (selected size = 2)
  1067.         ifTrue:    "exactly two selected glyphs"
  1068.             [equalitiesOnFirst _ IdentitySet new.
  1069.              (selected first) varsDo:
  1070.                 [: var |
  1071.                  var constraints copy do:
  1072.                     [: c |
  1073.                      (c isUserConstraint) ifTrue:
  1074.                         [equalitiesOnFirst add: c]]].
  1075.              (selected last) varsDo:
  1076.                 [: var |
  1077.                  var constraints copy do:
  1078.                     [: c |
  1079.                      ((c isUserConstraint) and:
  1080.                       [equalitiesOnFirst includes: c]) ifTrue:
  1081.                 [c destroyConstraint]]]]
  1082.         ifFalse:    "arbitrary number of selected glyphs"
  1083.             [selected do:
  1084.                 [: glyph |
  1085.                  glyph varsDo:
  1086.                     [: var |
  1087.                      var constraints copy do:
  1088.                         [: c |
  1089.                          (c isUserConstraint) ifTrue:
  1090.                             [c destroyConstraint]]]]]!
  1091. unmerge
  1092.     "Extract the selected items from any merges in which they participate."
  1093.  
  1094.     model selected do:
  1095.         [: glyph | glyph extractFromMerge].
  1096.     view computeEnclosingRectangle.
  1097.     view displayScene.! !
  1098.  
  1099. !SceneController methodsFor: 'menu support'!
  1100. addAndPlace: newGlyph
  1101.     "Add the given new glyph and let the user place it."
  1102.  
  1103.     | refPoint |
  1104.     model addGlyph: newGlyph.
  1105.     refPoint _ sensor cursorPoint.
  1106.     newGlyph moveTo: self adjustedCursorPoint.
  1107.     self
  1108.         while: [sensor anyButtonPressed not]
  1109.         move: (newGlyph locationPoints)
  1110.         refPoint: refPoint
  1111.         mergeWith: nil.!
  1112. argument
  1113.     "Answer the argument for unary operation from the model's selection. There must be exactly one object selected. If so, answer it. Otherwise, answer nil."
  1114.  
  1115.     (model selected size == 1)
  1116.         ifTrue: [^model selected asOrderedCollection first]
  1117.         ifFalse: [^nil].!
  1118. attachButton
  1119.     "Make the currently selected glyph behave as if it were a button."
  1120.  
  1121.     | host |
  1122.     host _ self argument.
  1123.     (host notNil) ifTrue:
  1124.         [model addGlyph: (AttachableButtonGlyph forHost: host)].!
  1125. attachMenu
  1126.     "Attach a menu to the currently selected glyph."
  1127.  
  1128.     | host |
  1129.     host _ self argument.
  1130.     (host notNil) ifTrue:
  1131.         [model addGlyph: (AttachableMenuGlyph forHost: host)].!
  1132. deleteGlyphs: deletedGlyphs
  1133.     "Delete all the given glyphs and their parents."
  1134.  
  1135.     | deletedSet |
  1136.     deletedSet _ IdentitySet new: deletedGlyphs size * 4.
  1137.     deletedSet addAll: deletedGlyphs.
  1138.     model topLevelGlyphs copy do:
  1139.         [: g |
  1140.          (g includesObjectIn: deletedSet) ifTrue:
  1141.             ["remove all constraints from the deleted glyph"
  1142.              g varsDo:
  1143.                 [: var |
  1144.                  var constraints copy do:
  1145.                      [: c | c destroyConstraint]].
  1146.              model removeGlyph: g]].
  1147.     model clearSelection.
  1148.     view computeEnclosingRectangle.
  1149.     view displayScene.!
  1150. mergeGlyphs: glyphsToMerge
  1151.     "Merge the glyphs in the given OrderedCollection, if they can be merged. The first glyph is the sink with which the remaining glyphs are merged."
  1152.  
  1153.     | sink |
  1154.     sink _ glyphsToMerge removeFirst.
  1155.     glyphsToMerge do:
  1156.         [: glyph |
  1157.          (glyph canMergeWith: sink) ifTrue:
  1158.             [glyph mergeWith: sink]].
  1159.     view computeEnclosingRectangle.
  1160.     view displayScene.!
  1161. partsMenu
  1162.     "Answer a hierarchical menu of glyph categories and glyphs."
  1163.     "Details: Building hierarchical menus is expensive, so we cache the menu and only rebuild it when a new glyph class is added or when the category of a glyph is changed."
  1164.  
  1165.     | categories categoryName s menuString |
  1166.     categories _ Dictionary new.
  1167.     Glyph allSubclasses do:
  1168.         [: c |
  1169.          categoryName _ c glyphCategory.
  1170.          (categoryName size > 0) ifTrue:
  1171.              [(categories includesKey: categoryName) ifFalse:
  1172.                 [categories at: categoryName put: (SortedCollection new)].
  1173.               (categories at: categoryName) add: c name]].
  1174.  
  1175.     s _ (String new: 200) writeStream.
  1176.     (categories keys asSortedCollection) do:
  1177.         [: categoryName |
  1178.          s nextPutAll: categoryName; nextPutAll: ': ('; cr.
  1179.          (categories at: categoryName) do:
  1180.             [: className |
  1181.              s nextPutAll: className.
  1182.              s nextPut: $[.
  1183.              s nextPutAll: className.
  1184.              s nextPut: $]; cr].
  1185.          s nextPut: $); cr].
  1186.     menuString _ s contents.
  1187.  
  1188.     (lastPartsMenuString isNil or:
  1189.      [lastPartsMenuString ~= menuString]) ifTrue:
  1190.         [partsMenuCache _
  1191.             (MenuBuilder parseFrom: menuString readStream) menu.
  1192.          lastPartsMenuString _ menuString].
  1193.  
  1194.     ^partsMenuCache!
  1195. removeButton
  1196.     "Remove the attached button from the currently selected glyph."
  1197.  
  1198.     | host buttons |
  1199.     host _ self argument.
  1200.     (host notNil) ifTrue:
  1201.         [buttons _
  1202.             model topLevelGlyphs select: [: g | g isMemberOf: AttachableButtonGlyph].
  1203.          buttons do:
  1204.              [: button |
  1205.              (button host == host) ifTrue:
  1206.                 [model removeGlyph: button]]].!
  1207. removeMenu
  1208.     "Remove the attached menu from the currently selected glyph."
  1209.  
  1210.     | host menus |
  1211.     host _ self argument.
  1212.     (host notNil) ifTrue:
  1213.         [menus _
  1214.             model topLevelGlyphs select: [: g | g isMemberOf: AttachableMenuGlyph].
  1215.          menus do:
  1216.              [: menu |
  1217.              (menu host == host) ifTrue:
  1218.                 [model removeGlyph: menu]]].! !
  1219.  
  1220. !SceneController methodsFor: 'direct manipulation'!
  1221. adjustedPoint: aPoint
  1222.     "Answer a point (in view coordinates) that is as close to aPoint (in screen coordinates) as possible."
  1223.  
  1224.     | borderBox adjustedPoint |
  1225.     borderBox _ view insetDisplayBox insetBy: 5.
  1226.     adjustedPoint _ aPoint copy.
  1227.     (aPoint x < borderBox left) ifTrue: [adjustedPoint x: borderBox left].
  1228.     (aPoint x > borderBox right) ifTrue: [adjustedPoint x: borderBox right].
  1229.     (aPoint y < borderBox top) ifTrue: [adjustedPoint y: borderBox top].
  1230.     (aPoint y > borderBox bottom) ifTrue: [adjustedPoint y: borderBox bottom].    
  1231.     ^adjustedPoint - view insetDisplayBox origin - view mouseOffset!
  1232. adjustOffsetForSelArea: aPoint
  1233.     "If aPoint (in screen coordinates) is outside my inset display box, try to scroll the view in that direction."
  1234.  
  1235.     | box pX pY left right top bottom new |
  1236.     box _ view insetDisplayBox.
  1237.     (box containsPoint: aPoint) ifTrue: [^self].
  1238.     pX _ aPoint x.
  1239.     pY _ aPoint y.
  1240.     left _ box left.
  1241.     right _ box right.
  1242.     top _ box top.
  1243.     bottom _ box bottom.
  1244.     new _ view scrollOffset.
  1245.     (pX < left) ifTrue: [new x: (new x + left - pX)].
  1246.     (pX > right) ifTrue: [new x: (new x + right - pX)].
  1247.     (pY < top) ifTrue: [new y: (new y + top - pY)].
  1248.     (pY > bottom) ifTrue: [new y: (new y + bottom - pY)].
  1249.     view scrollOffset: new.!
  1250. glyphAt: aPoint
  1251.     "Answer the selectable glyph at aPoint or nil if there isn't one."
  1252.  
  1253.     | adjustedPoint pointX pointY box |
  1254.     adjustedPoint _ aPoint - view insetDisplayBox origin - view mouseOffset.
  1255.     pointX _ adjustedPoint x.
  1256.     pointY _ adjustedPoint y.
  1257.     model selectableGlyphsDo:
  1258.         [: glyph |
  1259.          box _ glyph boundingBox.
  1260.          (box top <= pointY) ifTrue:
  1261.             [(box bottom >= pointY) ifTrue:
  1262.                 [(box left <= pointX) ifTrue:
  1263.                     [(box right >= pointX) ifTrue:
  1264.                         [(glyph containsPoint: adjustedPoint) ifTrue:
  1265.                             [^glyph]]]]]].
  1266.     ^nil        "no glyph found"!
  1267. moveAt: aPoint
  1268.     "Move all selected glyphs. If only one glyph is being moved, try to merge it with the glyph (if any) at its new location."
  1269.  
  1270.     | movingGlyphs onlyGlyph pointsToMove |
  1271.     movingGlyphs _ model selected asOrderedCollection.
  1272.     (movingGlyphs size = 1) ifTrue:
  1273.         [onlyGlyph _ movingGlyphs first].
  1274.     pointsToMove _ OrderedCollection new.
  1275.     movingGlyphs do:
  1276.         [: g | pointsToMove addAll: g locationPoints].
  1277.     self
  1278.         while: [sensor anyButtonPressed]
  1279.         move: pointsToMove
  1280.         refPoint: aPoint
  1281.         mergeWith: onlyGlyph.!
  1282. scrollAt: aPoint
  1283.     "As the user moves the cursor, change the offset of my model to scroll the view."
  1284.  
  1285.     | limits relOffset hotRect ratio |
  1286.     limits _ view scrollOffsetEnvelope.
  1287.     Cursor hand showWhile:
  1288.         [relOffset _
  1289.             (view scrollOffset * -40) / (limits extent max: (1@1)).
  1290.          hotRect _ (aPoint + relOffset - (40@40)) extent: 40@40.
  1291.          [sensor redButtonPressed] whileTrue:
  1292.              [ratio _ limits extent / hotRect extent.
  1293.              view scrollOffset:
  1294.                 (ratio * (sensor cursorPoint - hotRect corner)) rounded.
  1295.              view displayScene]].!
  1296. selectAreaAt: aPoint toggleFlag: toggleFlag
  1297.     "As the user moves the cursor, draw a selection rectangle, scrolling if the mouse leaves my view. When the red button is released, select all selectable glyphs inside the selection rectangle."
  1298.  
  1299.     | origin selectionRect viewForm doneOnce point corner |
  1300.     toggleFlag ifFalse: [model clearSelection].
  1301.     origin _ self adjustedPoint: aPoint.
  1302.     selectionRect _ origin extent: 0@0.
  1303.     doneOnce _ false.
  1304.     view computeBackground.
  1305.     [(sensor redButtonPressed) | doneOnce not] whileTrue:
  1306.          ["do this loop at least once"
  1307.           point _ sensor cursorPoint.
  1308.          self adjustOffsetForSelArea: point.
  1309.          corner _ self adjustedPoint: point.
  1310.          selectionRect _ Rectangle
  1311.             origin: (origin min: corner)
  1312.             extent: ((origin - corner) abs).
  1313.          view displayFeedbackWithBox: selectionRect width: 1.
  1314.          doneOnce _ true].
  1315.     model selectableGlyphsDo:
  1316.         [: p |
  1317.          (p intersects: selectionRect)
  1318.             ifTrue:
  1319.                 [toggleFlag
  1320.                     ifTrue: [model toggleSelect: p]
  1321.                     ifFalse: [model select: p]]].
  1322.     view displayScene.!
  1323. selectAt: aPoint toggleFlag: toggleFlag
  1324.     "Select the glyph at aPoint. If toggleFlag is true, add/remove the glyph to/from the selection. Otherwise add the glyph. If aPoint is not over any glyph then clear the selection."
  1325.  
  1326.     | glyph |
  1327.     glyph _ self glyphAt: aPoint.
  1328.     (glyph notNil)
  1329.         ifTrue:
  1330.             [((model selected includes: glyph) not & toggleFlag not)
  1331.                 ifTrue: [model clearSelection].
  1332.              toggleFlag
  1333.                 ifTrue: [model toggleSelect: glyph]
  1334.                 ifFalse: [model select: glyph]]
  1335.         ifFalse: [model clearSelection].!
  1336. while: testBlock move: pointsToMove refPoint: refPoint mergeWith: mergeGlyph 
  1337.     "Move the given points using mouse constraints. Any glyphs attached to the  
  1338.     points will follow the mouse until testBlock is false. If mergeGlyph is not nil, try  
  1339.     to merge it with the glyph (if any) at its new location."
  1340.  
  1341.     | mergeable mouseConstraints offset views mousePoint oldMousePoint target starterConstraints |
  1342.     mergeGlyph notNil
  1343.         ifTrue: 
  1344.             [mergeable _ OrderedCollection new: 100.
  1345.             model selectableGlyphsDo: [:g | (g includesObjectIn: pointsToMove)
  1346.                     ifFalse: [mergeable add: g]]].
  1347.     mouseConstraints _ OrderedCollection new.
  1348.     pointsToMove do: 
  1349.         [:p | 
  1350.         offset _ p - refPoint.
  1351.         mouseConstraints add: (XMouseConstraint
  1352.                 var: p xVar
  1353.                 strength: #preferred
  1354.                 offset: offset x); add: (YMouseConstraint
  1355.                 var: p yVar
  1356.                 strength: #preferred
  1357.                 offset: offset y)].
  1358.     thePlan notNil ifTrue: [].
  1359.     model isAnimated
  1360.         ifTrue: [starterConstraints _ mouseConstraints , model initialAnimationConstraints]
  1361.         ifFalse: [starterConstraints _ mouseConstraints].
  1362.     thePlan _ Planner extractPlanFromInputConstraints: starterConstraints.
  1363.     "views _ SceneView allInstances select: [: v | v isAlive].  
  1364.     views do: [: v | v computeBackground]."
  1365.     view computeBackground.
  1366.     [testBlock value]
  1367.         whileTrue: 
  1368.             [mousePoint _ sensor cursorPoint.
  1369.             (oldMousePoint ~= sensor cursorPoint or: [model isAnimated])
  1370.                 ifTrue: 
  1371.                     [target _ nil.
  1372.                     mergeGlyph notNil ifTrue: [mergeable do: [:g | ((g containsPoint: mousePoint + offset)
  1373.                                 and: [(g canMergeWith: mergeGlyph)
  1374.                                         or: [mergeGlyph canMergeWith: g]])
  1375.                                 ifTrue: [target _ g]]].
  1376.                     thePlan execute.
  1377.                     "views do:  
  1378.                     [: v |  
  1379.                      ((target notNil) and: [v == view])  
  1380.                     ifTrue:  
  1381.                     [v    displayFeedbackWithBox:  
  1382.                     (target boundingBox expandBy: 6)  
  1383.                     width: 2]  
  1384.                     ifFalse: [v displayFeedback]]]."
  1385.                     target notNil
  1386.                         ifTrue: [view displayFeedbackWithBox: (target boundingBox expandBy: 6)
  1387.                                 width: 2]
  1388.                         ifFalse: [view displayFeedback]].
  1389.             oldMousePoint _ mousePoint].
  1390.     mouseConstraints do: [:c | c destroyConstraint].
  1391.     target notNil ifTrue: [self mergeGlyphs: (OrderedCollection with: target with: mergeGlyph)].
  1392.     view computeEnclosingRectangle.
  1393.     view displayScene.
  1394.     model isAnimated
  1395.         ifTrue: 
  1396.             [thePlan _ model computeBackgroundPlan.
  1397.             view computeBackground]
  1398.         ifFalse: [thePlan _ nil]! !
  1399.  
  1400. !SceneController methodsFor: 'keyboard'!
  1401. readKeyboard
  1402.     "Keystrokes are sent to all selected Things that are interested in keyboard 
  1403.     input. "
  1404.  
  1405.     | selected interested char editVars editConstraints |
  1406.     selected _ model selected.
  1407.     interested _ IdentitySet new: 10.
  1408.     editVars _ IdentitySet new: 10.
  1409.     model inputGlyphsDo: [:g | (g wantsKeystrokes and: [selected includes: g])
  1410.             ifTrue: 
  1411.                 [interested add: g.
  1412.                 editVars addAll: g keystrokeVars]].
  1413.     editConstraints _ editVars collect: [:var | EditConstraint var: var strength: #preferred].
  1414.     thePlan notNil ifTrue: [].
  1415.     thePlan _ Planner extractPlanFromInputConstraints: editConstraints.
  1416.     view computeBackground.
  1417.     [sensor keyboardPressed]
  1418.         whileTrue: 
  1419.             [self resetTimer.
  1420.             char _ sensor keyboard.
  1421.             interested do: [:thing | thing handleKeystroke: char view: view].
  1422.             [(self timeOut: 300)
  1423.                 | sensor keyboardPressed]
  1424.                 whileFalse: ["wait a bit in case there is another character"
  1425.                     ].
  1426.             sensor keyboardPressed
  1427.                 ifFalse: 
  1428.                     [thePlan execute.
  1429.                     view displayFeedback]].
  1430.     editConstraints do: [:c | c destroyConstraint].
  1431.     "SceneView allInstancesDo: 
  1432.     [: v | 
  1433.      (v isAlive) ifTrue: 
  1434.     [v displaySafe: [v displayScene]]]."
  1435.     view isAlive ifTrue: [view displaySafe: [view displayScene]].
  1436.     model isAnimated
  1437.         ifTrue:
  1438.             [thePlan _ model computeBackgroundPlan.
  1439.             view computeBackground]
  1440.         ifFalse: [thePlan _ nil]! !
  1441.  
  1442. !SceneController methodsFor: 'mouse'!
  1443. adjustedCursorPoint
  1444.     "Answer the cursor point in adjusted view coordinates."
  1445.  
  1446.     ^sensor cursorPoint - view insetDisplayBox origin - view mouseOffset!
  1447. mouseGlyphAt: aPoint
  1448.     "Answer the mouse glyph at aPoint or nil if there isn't one."
  1449.  
  1450.     | adjustedPoint |
  1451.     adjustedPoint _ aPoint - view insetDisplayBox origin - view mouseOffset.
  1452.     model inputGlyphsDo:
  1453.         [: g |
  1454.          ((g wantsMouse) and:
  1455.            [g containsPoint: adjustedPoint]) ifTrue:
  1456.             [^g]].
  1457.  
  1458.     ^nil    "no input glyph found"!
  1459. passMouseTo: aGlyph
  1460.     "Allow the given glyph to handle a mouse interaction. It is assumed that the glyph wants the mouse."
  1461.  
  1462.     aGlyph handleMouseDown: self adjustedCursorPoint view: view.
  1463.     aGlyph handleMouseMove: self adjustedCursorPoint view: view.    
  1464.     [sensor anyButtonPressed] whileTrue:
  1465.         [aGlyph handleMouseMove: self adjustedCursorPoint view: view].
  1466.     aGlyph handleMouseUp: self adjustedCursorPoint view: view.
  1467.     view displayScene.! !
  1468.  
  1469. !ThreeDLine methodsFor: 'all'!
  1470. initialize
  1471.  
  1472.     p1 _ ThreeDPoint new.
  1473.     p2 _ ThreeDPoint new.!
  1474. p1
  1475.  
  1476.     ^p1!
  1477. p1: aThreeDPoint
  1478.  
  1479.     p1 _ aThreeDPoint.!
  1480. p2
  1481.  
  1482.     ^p2!
  1483. p2: aThreeDPoint
  1484.  
  1485.     p2 _ aThreeDPoint.! !
  1486.  
  1487. !SpringNodeCluster methodsFor: 'initialize-release'!
  1488. initialize
  1489.  
  1490.     node _ nil.
  1491.     springs _ OrderedCollection new.
  1492.     signs _ OrderedCollection new.
  1493.     vectors _ OrderedCollection new.
  1494.     anchored _ false.! !
  1495.  
  1496. !SpringNodeCluster methodsFor: 'accessing'!
  1497. anchored
  1498.  
  1499.     ^anchored!
  1500. node
  1501.  
  1502.     ^node!
  1503. signs
  1504.  
  1505.     ^signs!
  1506. springs
  1507.  
  1508.     ^springs!
  1509. vectors
  1510.  
  1511.     ^vectors! !
  1512.  
  1513. !SpringNodeCluster methodsFor: 'adding influences'!
  1514. addAnchor: anchor
  1515.  
  1516.     anchored _ true.
  1517.     (node == nil) ifTrue: [node _ anchor node].!
  1518. addP1InSpring: spring
  1519.  
  1520.     springs addLast: spring.
  1521.     signs addLast: -1.0.
  1522.     (node == nil) ifTrue: [node _ spring p1].!
  1523. addP2InSpring: spring
  1524.  
  1525.     springs addLast: spring.
  1526.     signs addLast: 1.0.
  1527.     (node == nil) ifTrue: [node _ spring p2].!
  1528. addVector: vector
  1529.  
  1530.     vectors add: vector.
  1531.     (node == nil) ifTrue: [node _ vector p1].! !
  1532.  
  1533. CWParser comment:
  1534. 'I parse a ConcertWare 4.0 music file to produce a Score. Various printing attributes (such as stem direction, beaming, and slurs) are thrown away, as is any text underlay. Repeat structure is currently ignored.
  1535.  
  1536. I could be modified to work with other versions of ConcertWare. I seem to work with ConcertWare 5.0 files that do not use certain new features.'!
  1537.  
  1538. !CWParser methodsFor: 'all'!
  1539. initConstants
  1540.     "Initialize tables used in parsing."
  1541.  
  1542.     twoByteCmds _
  1543.         #(1 2 4 5 6 7 8 9 10 11 12 13 15 16 17 18 19 127) collect:
  1544.             [: n | 256 - n].
  1545.  
  1546.     durTable _ Array new: 32 withAll: nil.
  1547.     durTable at: 1 put: 1.        "ninty-sixth"
  1548.     durTable at: 2 put: 2.        "thirty-second triplet"
  1549.     durTable at: 3 put: 3.        "thirty-second"
  1550.     durTable at: 4 put: 4.        "sixteenth triplet"
  1551.     durTable at: 6 put: 6.        "sixteenth"
  1552.     durTable at: 8 put: 8.        "eighth triplet"
  1553.     durTable at: 9 put: 9.        "dotted sixteenth"
  1554.     durTable at: 12 put: 12.    "eighth"
  1555.     durTable at: 16 put: 16.    "quarter triplet"
  1556.     durTable at: 18 put: 18.    "dotted eighth"
  1557.     durTable at: 24 put: 24.    "quarter"
  1558.     durTable at: 25 put: 36.    "dotted quarter"
  1559.     durTable at: 26 put: 32.    "half triplet"
  1560.     durTable at: 27 put: 48.    "half"
  1561.     durTable at: 28 put: 72.    "dotted half"
  1562.     durTable at: 29 put: 64.    "while triplet"
  1563.     durTable at: 30 put: 96.    "whole"
  1564.     durTable at: 31 put: 144.    "dotted whole"!
  1565. midiPitch: pitchByte
  1566.     "Extract and answer the Midi pitch designated by the given pitch byte. Answer zero if pitchByte designates a rest."
  1567.  
  1568.     | whiteKey pitch |
  1569.     (pitchByte = 0)
  1570.         ifTrue: [^0]    "a rest"
  1571.         ifFalse:
  1572.             ["not a rest"
  1573.              whiteKey _ (pitchByte bitAnd: 63).
  1574.              pitch _ 19 + ((whiteKey // 7) * 12) +
  1575.                     (#(0 2 4 5 7 9 10) at: (whiteKey \\ 7) + 1).
  1576.              ((pitchByte bitAnd: 64) > 0) ifTrue: [pitch _ pitch + 1].    "sharp"
  1577.              ((pitchByte bitAnd: 128) > 0) ifTrue: [pitch _ pitch - 1].    "flat"
  1578.              ^pitch].!
  1579. parse: aBinaryStream
  1580.     "Parse the given stream and answer a Score."
  1581.  
  1582.     self initConstants.
  1583.     inStream _ aBinaryStream.
  1584.     inStream reopen.
  1585.     self skipHeader.
  1586.     merger _ MergeSorter new.
  1587.     1 to: 8 do:
  1588.         [: v |
  1589.          voice _ v.
  1590.          self readVoice].
  1591.     ^merger asScore!
  1592. readChord
  1593.     "Add a new note to the last chord."
  1594.  
  1595.     | pitch dur |
  1596.     pitch _ self midiPitch: (inStream next).
  1597.     dur _ lastDur.
  1598.     (pitch ~= 0) ifTrue:
  1599.         ["if this note is not a rest, add it to the voice"
  1600.          merger add:
  1601.             (NoteElement
  1602.                 new: pitch
  1603.                 at: time - lastDur
  1604.                 dur: lastDur
  1605.                 vel: 60 voice: voice)].!
  1606. readCommand
  1607.     "Parse a voice command. If it is a note or end-of-voice command, process it. Otherwise, skip it."
  1608.  
  1609.     | cmd |
  1610.     "read the next command byte"
  1611.     cmd _ inStream next.
  1612.  
  1613.     "a note command"
  1614.     (cmd < 128) ifTrue: [^self readNote: cmd].
  1615.  
  1616.     "a chord command"
  1617.     (cmd = (256 - 18)) ifTrue:
  1618.         [^self readChord].
  1619.  
  1620.     "an end of voice command"
  1621.     (cmd = 128) ifTrue:
  1622.         [inStream next.    "skip second command byte"
  1623.          ^doneFlag _ true].
  1624.  
  1625.     "skip a two-byte command"
  1626.     (twoByteCmds includes: cmd) ifTrue:
  1627.         [^inStream next].
  1628.  
  1629.     "skip a text command"
  1630.     ((cmd >= (256 - 63)) & (cmd <= (256 - 48))) ifTrue:
  1631.         [^self skipText].
  1632.  
  1633.     "skip a variable length command"
  1634.     ((cmd >= (256 - 47)) & (cmd <= (256 - 32))) ifTrue:
  1635.         [^self skipVariableLength].
  1636.  
  1637.     "skip a four-byte command"
  1638.     ((cmd >= (256 - 79)) & (cmd <= (256 - 64))) ifTrue:
  1639.         [^inStream next: 3].
  1640.  
  1641.     self error: 'Implementation error: unexpected command'.!
  1642. readNote: cmd
  1643.     "Parse a note."
  1644.  
  1645.     | pitch dur note |
  1646.     pitch _ self midiPitch: (inStream next).
  1647.     dur _ (durTable at: (cmd bitAnd: 31)) * 3.
  1648.     (pitch = 0)
  1649.         ifTrue:
  1650.             ["this is a rest"
  1651.              (lastNote notNil) ifTrue:
  1652.                 ["cannot have a tie across a rest"
  1653.                  merger add: note.
  1654.                  lastNote _ nil].
  1655.              "cannot have a chord with a rest"
  1656.              lastDur _ nil]
  1657.         ifFalse:
  1658.             ["this is a note, NOT a rest"
  1659.              note _ NoteElement new: pitch at: time dur: dur vel: 60 voice: voice.
  1660.              (lastNote notNil) ifTrue:
  1661.                 [(lastNote pitch = note pitch)
  1662.                     ifTrue:
  1663.                         ["the last note is tied to this note"
  1664.                          note _ lastNote dur: (lastNote dur + note dur)]
  1665.                     ifFalse:
  1666.                         ["the last note is slurred, not tied, to this note"
  1667.                          merger add: lastNote]].
  1668.              ((cmd bitAnd: 96) > 0)
  1669.                 ifTrue:
  1670.                     ["this note is slurred or tied to the next note"
  1671.                      lastNote _ note]
  1672.                 ifFalse:
  1673.                     ["this note is NOT slurred or tied to the next note"
  1674.                      merger add: note.
  1675.                      lastNote _ nil].
  1676.              lastDur _ note dur].
  1677.     time _ time + dur.!
  1678. readVoice
  1679.     "Parse the notes of a voice, adding them the merge sorter."
  1680.  
  1681.     time _ 0.
  1682.     lastNote _ nil.
  1683.     lastDur _ nil.
  1684.     doneFlag _ false.
  1685.     merger startNewSublist.
  1686.     [doneFlag] whileFalse:
  1687.         [self readCommand].!
  1688. skipHeader
  1689.     "Skip the header of a ConcertWare 4.0 file."
  1690.  
  1691.     | version count |
  1692.     "check the version number, then skip the rest of the 56-byte fixed-size header"
  1693.     version _ inStream next: 4.
  1694.     (version asString = '4.01') ifFalse:
  1695.         [self error: 'Cannot read files produced by that version of ConcertWare'].
  1696.     inStream skip: 52.
  1697.  
  1698.     "skip variable-length fields"
  1699.     12 timesRepeat:
  1700.         [self skipVariableLength].
  1701.  
  1702.     "skip ruler record"
  1703.     inStream skip: 64.!
  1704. skipText
  1705.     "Skip a text record. A text record consists of a fifteen-byte fixed header followed by a string length byte followed by a string padded so as to make the total record length be even."
  1706.  
  1707.     | count |
  1708.     inStream skip: 15.
  1709.     count _ inStream next.
  1710.     inStream skip: count.
  1711.     (count even) ifTrue: [inStream next].    "make total record length even"!
  1712. skipVariableLength
  1713.     "Skip a variable length record. The first byte is the byte count of the remainder of the record."
  1714.  
  1715.     | count |
  1716.     count _ inStream next.
  1717.     inStream skip: count.! !
  1718.  
  1719. !ThreeDPoint methodsFor: 'all'!
  1720. addStays
  1721.  
  1722.     x defaultStay.
  1723.     y defaultStay.
  1724.     z defaultStay.!
  1725. equals: aThreeDPoint
  1726.  
  1727.     x requireEquals: aThreeDPoint xVar.
  1728.     y requireEquals: aThreeDPoint yVar.
  1729.     z requireEquals: aThreeDPoint zVar.!
  1730. initialize
  1731.  
  1732.     x _ FreeVariable value: 0.
  1733.     y _ FreeVariable value: 0.
  1734.     z _ FreeVariable value: 0.!
  1735. x: xValue y: yValue z: zValue
  1736.  
  1737.     x setValue: xValue.
  1738.     y setValue: yValue.
  1739.     z setValue: zValue.!
  1740. xVar
  1741.  
  1742.     ^x!
  1743. yVar
  1744.  
  1745.     ^y!
  1746. zVar
  1747.  
  1748.     ^z! !
  1749.  
  1750. !PopUpMenu methodsFor: 'controlling'!
  1751. startUpWithHeadingAndWaitForSelection: aString
  1752.     "Display and make a selection from the receiver as long as the button denoted
  1753.     by the symbol, aSymbol, is pressed.  Answer the current selection."
  1754.     
  1755.     self displayAt: Sensor cursorPoint withHeading: aString
  1756.         during: [[(Sensor anyButtonPressed and: [frame inside containsPoint: Sensor cursorPoint])]
  1757.                     whileFalse: [].
  1758.                 [self buttonPressed: #anyButton]
  1759.                     whileTrue: [self manageMarker]].
  1760.     ^selection! !
  1761.  
  1762. CustomMenu comment:
  1763. 'I am used to build menus on-the-fly. I maintain lists of menu items, actions (usually symbols to be sent as messages), and menu section dividing lines to which my clients may append new entries and lines by sending me the messages:
  1764.  
  1765.     add: aString action: anAction
  1766.     addLine
  1767.  
  1768. After the menu is constructed, it may be invoked with one of the following messages:
  1769.  
  1770.     invoke: initialSelection
  1771.     invoke
  1772.  
  1773. I am a subclass of ActionMenu, so I inherit a number of instance variables. The ones I am particularly concerned with are:
  1774.  
  1775.     items _ an OrderedCollection of strings to appear in the menu
  1776.     selectors _ an OrderedCollection of Symbols to be used as message selectors
  1777.     lineArray _ an OrderedCollection of line positions
  1778.     lastLine _ used to keep track of the last line to avoid making duplicate entries in lineArray'!
  1779.  
  1780. !CustomMenu methodsFor: 'initialize-release'!
  1781. initialize
  1782.  
  1783.     items _ OrderedCollection new.
  1784.     selectors _ OrderedCollection new.
  1785.     lineArray _ OrderedCollection new.
  1786.     lastLine _ 0.! !
  1787.  
  1788. !CustomMenu methodsFor: 'construction'!
  1789. add: aString action: aSymbol
  1790.     "Add the given string as the next menu item. If it is selected, the given action (usually but not necessarily a symbol) will be returned to the client."
  1791.  
  1792.     items addLast: aString.
  1793.     selectors addLast: aSymbol.!
  1794. addLine
  1795.     "Append a line to the menu after the last entry. Suppress duplicate lines."
  1796.  
  1797.     (lastLine ~= items size)
  1798.         ifTrue:
  1799.             [lastLine _ items size.
  1800.              lineArray addLast: lastLine].! !
  1801.  
  1802. !CustomMenu methodsFor: 'invocation'!
  1803. invoke
  1804.     "Invoke the menu with no initial selection."
  1805.  
  1806.     ^self invoke: nil!
  1807. invoke: initialSelection
  1808.     "Invoke the menu with the given initial selection (i.e. one of my 'action' symbols). Answer the 'action' selector associated with the menu item chosen by the user or nil if none is chosen."
  1809.  
  1810.     | itemIndex |
  1811.     self build.
  1812.     (initialSelection notNil)
  1813.         ifTrue: [self preSelect: initialSelection].
  1814.     itemIndex _ self startUp.
  1815.     (itemIndex = 0)
  1816.         ifTrue: [^nil]
  1817.         ifFalse: [^selectors at: itemIndex].! !
  1818.  
  1819. !CustomMenu methodsFor: 'private'!
  1820. build
  1821.     "Turn myself into an invokable ActionMenu."
  1822.  
  1823.     | stream itemIndex |
  1824.     stream _ WriteStream on: (String new).
  1825.     items do: [: item | stream nextPutAll: item; cr].
  1826.     (items isEmpty)
  1827.         ifFalse: [stream skip: -1].     "remove last cr"
  1828.     self labels: stream contents font: (TextStyle default fontAt: 1) lines: lineArray.!
  1829. preSelect: action
  1830.     "Pre-select and highlight the menu item associated with the given action."
  1831.  
  1832.     | i |
  1833.     i _ selectors indexOf: action ifAbsent: [^self].
  1834.     self reset.
  1835.     marker _ marker 
  1836.         align: marker topLeft 
  1837.         with: (marker left)@(frame inside top + (marker height * (i - 1))).
  1838.     selection _ i.! !
  1839.  
  1840. Strength comment:
  1841. 'Strengths are used to measure the relative importance of constraints. The hierarchy of available strengths is determined by the class variable StrengthTable (see my class initialization method). Because Strengths are invariant, references to Strength instances are shared (i.e. all references to "Strength of: #required" point to a single, shared instance). New strengths may be inserted in the strength hierarchy without disrupting current constraints.'!
  1842.  
  1843. !Strength methodsFor: 'comparing'!
  1844. sameAs: aStrength
  1845.     "Answer true if I am the same strength as the given Strength."
  1846.  
  1847.     ^arithmeticValue = aStrength arithmeticValue!
  1848. stronger: aStrength
  1849.     "Answer true if I am stronger than the given Strength."
  1850.  
  1851.     ^arithmeticValue < aStrength arithmeticValue!
  1852. weaker: aStrength
  1853.     "Answer true if I am weaker than the given Strength."
  1854.  
  1855.     ^arithmeticValue > aStrength arithmeticValue! !
  1856.  
  1857. !Strength methodsFor: 'max/min'!
  1858. strongest: aStrength
  1859.     "Answer the stronger of myself and aStrength."
  1860.  
  1861.     (aStrength stronger: self)
  1862.         ifTrue: [^aStrength]
  1863.         ifFalse: [^self].!
  1864. weakest: aStrength
  1865.     "Answer the weaker of myself and aStrength."
  1866.  
  1867.     (aStrength weaker: self)
  1868.         ifTrue: [^aStrength]
  1869.         ifFalse: [^self].! !
  1870.  
  1871. !Strength methodsFor: 'printing'!
  1872. printOn: aStream
  1873.     "Append a string which represents my strength onto aStream."
  1874.  
  1875.     aStream nextPutAll: '%', symbolicValue, '%'.! !
  1876.  
  1877. !Strength methodsFor: 'private'!
  1878. arithmeticValue
  1879.     "Answer my arithmetic value. Used for comparisons. Note that STRONGER constraints have SMALLER arithmetic values."
  1880.  
  1881.     ^arithmeticValue!
  1882. initializeWith: symVal
  1883.     "Record my symbolic value and reset my arithmetic value."
  1884.  
  1885.     symbolicValue _ symVal.
  1886.     self resetValue.!
  1887. initializeWith: symVal and: numVal
  1888.     symbolicValue _ symVal.
  1889.     arithmeticValue _ numVal!
  1890. resetValue
  1891.     "Lookup my symbolic value in the StrengthTable and reset my internal value."
  1892.  
  1893.     arithmeticValue _ StrengthTable at: symbolicValue.! !
  1894.  
  1895. !BitBlt methodsFor: 'Minstrel'!
  1896. drawFrom: p1 to: p2
  1897.     "This line drawing method was improved by John Maloney to do more intelligent clipping. If the line (p1,p2) is entirely INSIDE the clipping box, this method gives results that are identical to the original line drawing method. If the line is entirely OUTSIDE the clipping box, it detects this early and avoids the cost of drawing it. Finally, if the line is PARTIALLY inside the clipping box, the portion entirely inside the clipping box computed and can be drawn by the primitive. If the pen form is large, you may notice a slight difference from the results given by the normal drawFrom:to: method on the right/bottom of the clipping box."
  1898.  
  1899.     | offset startPoint endPoint clipOrigin clipCorner clippedLine |
  1900.     width _ sourceForm width.
  1901.     height _ sourceForm height.
  1902.     offset _ sourceForm offset.
  1903.  
  1904.     "always draw down, or at least left-to-right"
  1905.     ((p1 y = p2 y and: [p1 x < p2 x])
  1906.         or: [p1 y < p2 y])
  1907.             ifTrue: [startPoint _ p1 + offset. endPoint _ p2 + offset]
  1908.             ifFalse: [startPoint _ p2 + offset. endPoint _ p1 + offset].
  1909.  
  1910.     "The clipping rectangle specified by the sender is intersected with the destination form. Then the corner of the result is inset by the extent of the pen form. This clipping rectangle is used to compute 'clippedLine'. clipped line is a triple <visibleFlag, startPoint, endPoint>. If visibleFlag is false, no part of the line is visible in the clipping box. If visibleFlag is true, clippedLine can be drawn with the primitive, which is fast."
  1911.     clipOrigin _ (clipX@clipY) max: (0@0).
  1912.     clipCorner _ (clipWidth@clipHeight) min: (destForm extent).
  1913.     clippedLine _
  1914.         (ClippingRectangle
  1915.             origin: clipOrigin
  1916.             corner: clipCorner - (width@height))
  1917.                 clipFrom: startPoint to: endPoint.
  1918.  
  1919.     (clippedLine first)
  1920.         ifTrue:
  1921.             ["draw the visible part of the line"
  1922.              self privateDrawFrom: (clippedLine at: 2) to: (clippedLine at: 3)]
  1923.         ifFalse:
  1924.             ["the line is entirely outside the clipping region"].!
  1925. privateDrawFrom: p1 to: p2
  1926.     "Added by John Maloney for faster line drawing."
  1927.  
  1928.     destX _ p1 x rounded.
  1929.     destY _ p1 y rounded.
  1930.     self drawLoopX: ((p2 x - p1 x) rounded) Y: ((p2 y - p1 y) rounded)! !
  1931.  
  1932. QuickPrint comment:
  1933. 'This class supports fast character string display. It is significantly faster than using a Paragraph for the same purpose.'!
  1934.  
  1935. !QuickPrint methodsFor: 'displaying'!
  1936. drawString: aString
  1937.     "Draw the given string."
  1938.  
  1939.     destX _ clipX.
  1940.     destY _ clipY.
  1941.     self
  1942.         scanCharactersFrom: 1
  1943.         to: (aString size)
  1944.         in: aString
  1945.         rightX: (clipX + clipWidth)
  1946.         stopConditions: stopConditions
  1947.         displaying: true!
  1948. stringWidth: aString
  1949.     "Answer the width of the given string."
  1950.  
  1951.     destX _ 0.
  1952.     destY _ 0.
  1953.     self
  1954.         scanCharactersFrom: 1
  1955.         to: (aString size)
  1956.         in: aString
  1957.         rightX: 10000    "virtual infinity"
  1958.         stopConditions: stopConditions
  1959.         displaying: false.
  1960.     ^destX! !
  1961.  
  1962. !QuickPrint methodsFor: 'positioning'!
  1963. downBy: offset
  1964.     "Move the top border of my clipping box down by the given amount."
  1965.  
  1966.     | clipBox |
  1967.     clipBox _ self clipRect.
  1968.     clipBox top: ((clipBox top + offset) min: clipBox bottom).
  1969.     self clipRect: clipBox.!
  1970. lineHeight
  1971.     "Answer the height of the font used by QuickPrint."
  1972.  
  1973.     ^font height!
  1974. rightBy: offset
  1975.     "Move the left border of my clipping box right by the given amount."
  1976.  
  1977.     | clipBox |
  1978.     clipBox _ self clipRect.
  1979.     clipBox left: ((clipBox left + offset) min: clipBox right).
  1980.     self clipRect: clipBox.! !
  1981.  
  1982. !QuickPrint methodsFor: 'private'!
  1983. newOn: aForm box: aRectangle font: aStrikeFont
  1984.     "Initialize myself with the given font."
  1985.  
  1986.     textStyle _ TextStyle default.
  1987.     font _ aStrikeFont.
  1988.     destForm _ aForm.
  1989.     halftoneForm _ Form black.
  1990.     combinationRule _ Form over.
  1991.     self clipRect: aRectangle.
  1992.     sourceY _ 0.
  1993.     "sourceX is set when selecting the character from the font strike bitmap"
  1994.     self setStopConditions.!
  1995. setFont: newFont
  1996.     "Set my font."
  1997.  
  1998.     font _ newFont.
  1999.     self setStopConditions.!
  2000. setStopConditions
  2001.     "Set default stop conditions for the font."
  2002.  
  2003.     spaceWidth _ font spaceWidth. 
  2004.     sourceForm _ font glyphs.
  2005.     xTable _ font xTable.
  2006.     height _ font height.
  2007.     stopConditions _ font stopConditions.
  2008.     stopConditions at: CR asInteger + 1 put: #cr.
  2009.     stopConditions at: 10 + 1 put: #cr.
  2010.     stopConditions at: Space asInteger + 1 put: nil.    "don't justify"
  2011.     stopConditions at: EndOfRun put: #endOfRun.
  2012.     stopConditions at: CrossedX put: #crossedX.
  2013.     stopConditions at: Ctrls asInteger + 1 put: #onePixelSpace.
  2014.     stopConditions at: CtrlS asInteger + 1 put: #onePixelBackspace.
  2015.     stopConditions at: Ctrlz asInteger + 1 put: #characterNotInFont.! !
  2016.  
  2017. PaletteButton comment:
  2018. 'I support simple buttons. I have a Form for displaying myself and set of client-supplied blocks for performing actions on button down, button up, and abort (mouse up outside the button).'!
  2019.  
  2020. !PaletteButton methodsFor: 'initialize-release'!
  2021. form: aForm position: aPoint
  2022.  
  2023.     form _ aForm.
  2024.     position _ aPoint.
  2025.     view _ nil.    "The view must be initialized before this button can be used."
  2026.     downAction _ whileDownAction _ [].
  2027.     commitAction _ abortAction _ [].
  2028.     activeTest _ [true].
  2029.     onTest _ [false].!
  2030. release
  2031.  
  2032.     form _ nil.
  2033.     position _ nil.
  2034.     view _ nil.
  2035.     downAction _ whileDownAction _ nil.
  2036.     commitAction _ abortAction _ nil.
  2037.     activeTest _ onTest _ nil.! !
  2038.  
  2039. !PaletteButton methodsFor: 'access'!
  2040. abortAction: aBlock
  2041.  
  2042.     abortAction _ aBlock.!
  2043. absolutePosition
  2044.  
  2045.     ^view insetDisplayBox origin + position!
  2046. activeTest: aBlock
  2047.  
  2048.     activeTest _ aBlock.!
  2049. commitAction: aBlock
  2050.  
  2051.     commitAction _ aBlock.!
  2052. downAction: aBlock
  2053.  
  2054.     downAction _ aBlock.!
  2055. form: aForm
  2056.  
  2057.     form _ form.!
  2058. onTest: aBlock
  2059.  
  2060.     onTest _ aBlock.!
  2061. view: aView
  2062.  
  2063.     view _ aView.!
  2064. whileDownAction: aBlock
  2065.  
  2066.     whileDownAction _ aBlock.! !
  2067.  
  2068. !PaletteButton methodsFor: 'operation'!
  2069. display
  2070.     "Display myself, taking into account my state (active/non-active, on/off)."
  2071.  
  2072.     | box where |
  2073.     box _ view insetDisplayBox.
  2074.     where _ self absolutePosition.
  2075.     (activeTest value) ifFalse:
  2076.         [form
  2077.             displayOn: Display at: where clippingBox: box
  2078.             rule: Form over mask: Form gray].
  2079.  
  2080.     form
  2081.         displayOn: Display at: where clippingBox: box
  2082.         rule: Form over mask: Form black.
  2083.  
  2084.     (onTest value) ifTrue:
  2085.         [Display reverse:
  2086.             ((form computeBoundingBox expandBy: -1)
  2087.                 translateBy: where)].!
  2088. hasCursor
  2089.     "Answer true if I contain the cursor."
  2090.  
  2091.     ^form computeBoundingBox containsPoint:
  2092.         (Sensor cursorPoint - self absolutePosition)!
  2093. respond
  2094.     "Respond and answer true if the mouse button goes up over me."
  2095.  
  2096.     ((activeTest value) and: [self hasCursor])
  2097.         ifFalse: [^false].    "not active or cursor not over me"
  2098.  
  2099.     self showResponse.    "assume I am visible"
  2100.     downAction value.
  2101.     [Sensor anyButtonPressed]
  2102.         whileTrue:
  2103.             [whileDownAction value.
  2104.              (self hasCursor) ifFalse:
  2105.                 [abortAction value.
  2106.                  self showResponse.
  2107.                  self display.
  2108.                  ^false]].
  2109.     commitAction value.
  2110.     self showResponse.
  2111.     self display.
  2112.     ^true!
  2113. showResponse
  2114.     "Display feedback indicating that I have been pressed. Assume that I am entirely visible (don't bother with clipping)."
  2115.  
  2116.     Display
  2117.         border: ((form computeBoundingBox expandBy: 2)
  2118.                     translateBy: self absolutePosition)
  2119.         width: 2
  2120.         rule: Form reverse
  2121.         mask: Form black.! !
  2122.  
  2123. Planner comment:
  2124. 'I embody the DeltaBlue algorithm described in:
  2125.     "The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver"
  2126.     by Bjorn N. Freeman-Benson and John Maloney
  2127. See January 1990 Communications of the ACM or University of Washington TR 89-08-06 for further details.'!
  2128.  
  2129. !ThreeDDemo methodsFor: 'all'!
  2130. cube
  2131.     "Answer a set variable containing the ThreeDLines comprising a cube."
  2132.  
  2133.     | points lines |
  2134.     points _
  2135.        (Array
  2136.         with: ((ThreeDPoint x: 0 y: 0 z: 0) addStays)
  2137.         with: ((ThreeDPoint x: 100 y: 0 z: 0) addStays)
  2138.         with: ((ThreeDPoint x: 0 y: 100 z: 0) addStays)
  2139.         with: ((ThreeDPoint x: 0 y: 0 z: 100) addStays)),
  2140.        (Array
  2141.         with: ((ThreeDPoint x: 100 y: 100 z: 0) addStays)
  2142.         with: ((ThreeDPoint x: 100 y: 0 z: 100) addStays)
  2143.         with: ((ThreeDPoint x: 0 y: 100 z: 100) addStays)
  2144.         with: ((ThreeDPoint x: 100 y: 100 z: 100) addStays)).
  2145.     lines _ FreeVariable value: (TracedCollection new).
  2146.     #((1 2) (2 5) (5 3) (3 1)
  2147.         (4 6) (6 8) (8 7) (7 4)
  2148.         (1 4) (2 6) (3 7) (5 8)) do:
  2149.         [: connection |
  2150.          lines value add:
  2151.             ((ThreeDLine new)
  2152.                 p1: (points at: connection first);
  2153.                 p2: (points at: connection last))].
  2154.     ^lines!
  2155. tetrahedron
  2156.     "Answer a set variable containing the ThreeDLines comprising a tetrahedron."
  2157.  
  2158.     | points lines |
  2159.     points _ Array
  2160.         with: ((ThreeDPoint x: 0 y: 0 z: 0) addStays)
  2161.         with: ((ThreeDPoint x: 0 y: 60 z: 0) addStays)
  2162.         with: ((ThreeDPoint x: 60 y: 0 z: 0) addStays)
  2163.         with: ((ThreeDPoint x: 30 y: 30 z: 30) addStays).
  2164.     lines _ FreeVariable value: (TracedCollection new).
  2165.     #((1 2) (2 3) (3 1)
  2166.         (1 4) (2 4) (3 4)) do:
  2167.         [: connection |
  2168.          lines value add:
  2169.             ((ThreeDLine new)
  2170.                 p1: (points at: connection first);
  2171.                 p2: (points at: connection last))].
  2172.     ^lines!
  2173. threeDDemo
  2174.     "Make an x-y 2-D projection of a 3-D scene."
  2175.     "ThreeDDemo new threeDDemo"
  2176.  
  2177.     | lines view1 view2 view3 mapC thetaSlider phiSlider sinConstraint cosConstraint sinTheta cosTheta sinPhi cosPhi |
  2178.     lines _ self cube.
  2179.     "lines _ self tetrahedron."
  2180.     view1 _Scene new.
  2181.     view2 _ Scene new.
  2182.     view3 _ Scene new.
  2183.  
  2184.     mapC _ (BijectiveMapConstraint new)
  2185.         fromSet: lines toSet: (view1 glyphsVar)
  2186.         fromClass: ThreeDLine toClass: LineGlyph
  2187.         strength: #required.
  2188.     mapC offset: #p1.xVar from: #p1.xVar by: 60 strength: #required.
  2189.     mapC offset: #p1.yVar from: #p1.yVar by: 60 strength: #required.
  2190.     mapC offset: #p2.xVar from: #p2.xVar by: 60 strength: #required.
  2191.     mapC offset: #p2.yVar from: #p2.yVar by: 60 strength: #required.
  2192.  
  2193.     mapC _ (BijectiveMapConstraint new)
  2194.         fromSet: lines toSet: view2 glyphsVar
  2195.         fromClass: ThreeDLine toClass: LineGlyph
  2196.         strength: #required.
  2197.     mapC offset: #p1.xVar from: #p1.xVar by: 60 strength: #required.
  2198.     mapC offset: #p1.yVar from: #p1.zVar by: 60 strength: #required.
  2199.     mapC offset: #p2.xVar from: #p2.xVar by: 60 strength: #required.
  2200.     mapC offset: #p2.yVar from: #p2.zVar by: 60 strength: #required.
  2201.  
  2202.     thetaSlider _ (HSliderGlyph new)
  2203.         minVal: 0.0; maxVal: (2.0 * Float pi);
  2204.         moveTo: 80@12.
  2205.     view3 addGlyph: thetaSlider.
  2206.     phiSlider _ (HSliderGlyph new)
  2207.         minVal: 0.0; maxVal: (2.0 * Float pi);
  2208.         moveTo: 80@32.
  2209.     view3 addGlyph: phiSlider.
  2210.  
  2211.     sinConstraint _ Constraint
  2212.         names: #(angle sine) methods: #('sine _ angle sin').
  2213.     cosConstraint _ Constraint
  2214.         names: #(angle cosine) methods: #('cosine _ angle cos').
  2215.     sinTheta _ FreeVariable new.
  2216.     cosTheta _ FreeVariable new.
  2217.     sinPhi _ FreeVariable new.
  2218.     cosPhi _ FreeVariable new.
  2219.     (sinConstraint copy) var: (thetaSlider valueVar) var: sinTheta strength: #required.
  2220.     (cosConstraint copy) var: (thetaSlider valueVar) var: cosTheta strength: #required.
  2221.     (sinConstraint copy) var: (phiSlider valueVar) var: sinPhi strength: #required.
  2222.     (cosConstraint copy) var: (phiSlider valueVar) var: cosPhi strength: #required.
  2223.  
  2224.     mapC _ (BijectiveMapConstraint new)
  2225.         fromSet: lines toSet: (view3 glyphsVar)
  2226.         fromClass: ThreeDLine toClass: LineGlyph
  2227.         strength: #required.
  2228.     mapC addPairwiseConstraint: ((ThreeDtoTwoDLineConstraint new)
  2229.         type: #x point: #p1 sinTheta: sinTheta cosTheta: cosTheta sinPhi: sinPhi cosPhi: cosPhi).
  2230.     mapC addPairwiseConstraint: ((ThreeDtoTwoDLineConstraint new)
  2231.         type: #y point: #p1 sinTheta: sinTheta cosTheta: cosTheta sinPhi: sinPhi cosPhi: cosPhi).
  2232.     mapC addPairwiseConstraint: ((ThreeDtoTwoDLineConstraint new)
  2233.         type: #x point: #p2 sinTheta: sinTheta cosTheta: cosTheta sinPhi: sinPhi cosPhi: cosPhi).
  2234.     mapC addPairwiseConstraint: ((ThreeDtoTwoDLineConstraint new)
  2235.         type: #y point: #p2 sinTheta: sinTheta cosTheta: cosTheta sinPhi: sinPhi cosPhi: cosPhi).
  2236.  
  2237.     SceneView openNoTerminateOn: view1.
  2238.     SceneView openNoTerminateOn: view2.
  2239.     SceneView openNoTerminateOn: view3.
  2240.     Processor terminateActive! !
  2241.  
  2242. AbstractConstraint comment:
  2243. 'I represent a system-maintainable relationship (or "constraint") between a set of variables. I contain a set of methods that can be executed to enforce the constraint. If I am satisfied in the current data flow graph, the method used to enforce the relationship is stored in whichMethod. If I am not satisfied, whichMethod is nil.
  2244.  
  2245. Instance variables:
  2246.     strength            the strength of this constraint <Strength>
  2247.     variables        the constrained variables <Array of DBVariable>
  2248.     methods            a collection of methods that can be used to
  2249.                     enforce this constraint <Array of Method>
  2250.     whichMethod        the method currently used to enforce this constraint
  2251.                     or nil if this constraint is not satisfied <Method>'!
  2252.  
  2253. !AbstractConstraint methodsFor: 'accessing'!
  2254. name: n
  2255.     name _ n!
  2256. strength
  2257.     "Answer my strength."
  2258.  
  2259.     ^strength!
  2260. strength: strengthSymbol
  2261.     "Set my strength."
  2262.  
  2263.     strength _ Strength of: strengthSymbol.! !
  2264.  
  2265. !AbstractConstraint methodsFor: 'queries'!
  2266. includeInPlan
  2267.     "Answer true if this constraint should be included in the plan. Subclasses such as EditConstraint and StayConstraint override this method to return 'false', since they are noops at plan execution time."
  2268.  
  2269.     ^true!
  2270. isInput
  2271.     "Normal constraints are not input constraints. An input constraint is one that depends on external state, such as the mouse, the keyboard, a clock, or some arbitrary piece of imperative code."
  2272.  
  2273.     ^false!
  2274. isLayoutConstraint
  2275.     "Normal constraints are not layout constraints."
  2276.  
  2277.     ^false!
  2278. isMergeConstraint
  2279.     "Normal constraints are not merge constraints."
  2280.  
  2281.     ^false!
  2282. isRequired
  2283.     "Answer true if this constraint is a required constraint."
  2284.  
  2285.     ^strength sameAs: (Strength required)!
  2286. isSatisfied
  2287.     "Answer true if this constraint is satisfied in the current solution."
  2288.  
  2289.     self subclassResponsibility!
  2290. isUserConstraint
  2291.     "Normal constraints are not user constraints."
  2292.  
  2293.     ^false! !
  2294.  
  2295. !AbstractConstraint methodsFor: 'add/remove'!
  2296. addConstraint
  2297.     "Activate this constraint and attempt to satisfy it."
  2298.  
  2299.     self addToGraph.
  2300.     Planner incrementalAdd: self.!
  2301. addToGraph
  2302.     "Add myself to the constraint graph."
  2303.  
  2304.     self subclassResponsibility!
  2305. destroyConstraint
  2306.     "Remove and release the constraint."
  2307.  
  2308.     self removeConstraint.
  2309.     self release.!
  2310. removeConstraint
  2311.     "Deactivate this constraint and remove it from the constraint graph, possibly causing other constraints to be satisfied."
  2312.  
  2313.     (self isSatisfied) ifTrue: [Planner incrementalRemove: self].
  2314.     self removeFromGraph.!
  2315. removeFromGraph
  2316.     "Remove myself from the constraint graph."
  2317.  
  2318.     self subclassResponsibility! !
  2319.  
  2320. !AbstractConstraint methodsFor: 'printing'!
  2321. longPrintOn: aStream
  2322.  
  2323.     | bindings |
  2324.     aStream nextPut: $(.
  2325.     self shortPrintOn: aStream.
  2326.     aStream space; nextPutAll: self strength printString.
  2327.     (self isSatisfied)
  2328.         ifTrue:
  2329.             [aStream cr; space; space; space.
  2330.              self inputsDo:
  2331.                 [: in | aStream nextPutAll: 'v', in asOop printString, '(', in value printString, ') '].
  2332.             aStream nextPutAll: '-> '.
  2333.             aStream nextPutAll: 'v', self output asOop printString, '(', self output value printString, ')']
  2334.         ifFalse:
  2335.             [aStream space; nextPutAll: 'UNSATISFIED'].
  2336.     aStream nextPut: $)!
  2337. printOn: aStream
  2338.  
  2339.     (Sensor leftShiftDown)
  2340.         ifTrue: [self longPrintOn: aStream]
  2341.         ifFalse: [self shortPrintOn: aStream].!
  2342. shortPrintOn: aStream
  2343.  
  2344.     aStream nextPutAll: self class name.
  2345.     aStream nextPutAll: '(', self asOop printString.
  2346.     name notNil ifTrue: [aStream nextPutAll: ' "', name, '"'].
  2347.     aStream nextPut: $)! !
  2348.  
  2349. !AbstractConstraint methodsFor: 'planning'!
  2350. chooseMethod: mark
  2351.     "Decide if I can be satisfied and record that decision. The output of the choosen method must be not have the given mark and must have a walkabout strength less than that of this constraint."
  2352.  
  2353.     self subclassResponsibility!
  2354. inputsDo: aBlock
  2355.     "Assume that I am satisfied. Evaluate the given block on all my current input variables."
  2356.  
  2357.     self subclassResponsibility!
  2358. inputsKnown: mark
  2359.     "Assume that I am satisfied. Answer true if all my current inputs are known. A variable is known if either a) it is 'stay' (i.e. it is a constant at plan execution time), b) it has the given mark (indicating that it has been computed by a constraint appearing earlier in the plan), or c) it is not determined by any constraint. The last provision is for past states of history variables, which are not marked stay but which do not depend on any constraint being already in the plan."
  2360.  
  2361.     self inputsDo:
  2362.         [: in |
  2363.          ((in stay) or: [(in mark = mark) or: [in determinedBy == nil]]) ifFalse:
  2364.             [^false]].
  2365.     ^true!
  2366. markUnsatisfied
  2367.     "Record the fact that I am unsatisfied."
  2368.  
  2369.     self subclassResponsibility!
  2370. output
  2371.     "Answer my current output variable. Raise an error if I am not currently satisfied."
  2372.  
  2373.     self subclassResponsibility!
  2374. possibleMethodsDo: aBlock
  2375.     "Evaluate the given block for all potential methods of this constraint. The block takes two arguments. The first is a list of inputs for the method. The second is the output for the method."
  2376.  
  2377.     self subclassResponsibility!
  2378. recalculate
  2379.     "Calculate the walkabout strength, the stay flag, and, if it is 'stay', the value for the current output of this constraint, and answer the current output variable. Assume this constraint is satisfied."
  2380.  
  2381.     self subclassResponsibility!
  2382. satisfy: mark
  2383.     "Attempt to find a way to enforce this constraint. If successful, record the solution, perhaps modifying the current dataflow graph. Answer the constraint that this constraint overrides, if there is one, or nil, if there isn't."
  2384.     "Assume: I am not already satisfied"
  2385.  
  2386.     | overridden out |
  2387.     self chooseMethod: mark.
  2388.     (self isSatisfied)
  2389.         ifTrue:            "constraint can be satisfied"
  2390.             ["mark inputs to allow cycle detection in addPropagate"
  2391.              self inputsDo: [: in | in mark: mark].
  2392.              out _ self output.
  2393.              overridden _ out determinedBy.
  2394.              (overridden == nil) ifFalse: [overridden markUnsatisfied].
  2395.              out determinedBy: self.
  2396.              (Planner addPropagate: self mark: mark) ifFalse:
  2397.                 [self notify:
  2398.                     ('Cycle encountered adding:\   ',
  2399.                      self printString,
  2400.                      '\Constraint removed.') withCRs.
  2401.                  ^nil].
  2402.              out mark: mark]
  2403.         ifFalse:            "constraint cannot be satisfied"
  2404.             [overridden _ nil.
  2405.              (self isRequired) ifTrue:
  2406.                 [self notify: 'Failed to satisfy a required constraint']].
  2407.     ^overridden! !
  2408.  
  2409. !AbstractConstraint methodsFor: 'execution'!
  2410. codeStringFor: variableDictionary on: aStream
  2411.     "Append to the given stream a Smalltalk string that can be compiled to enforce this constraint. variableDictionary is a Dictionary mapping each constrained variable to a string to be used to reference that variable."
  2412.  
  2413.     self error: 'This constraint cannot be compiled'!
  2414. execute
  2415.     "Enforce this constraint. Assume that it is satisfied."
  2416.  
  2417.     self subclassResponsibility! !
  2418.  
  2419. Constraint comment:
  2420. 'I represent a system-maintainable relationship (or "constraint") between a set of variables. I contain a set of methods that can be executed to enforce the constraint. If I am satisfied in the current data flow graph, the method used to enforce the relationship is stored in whichMethod. If I am not satisfied, whichMethod is nil.
  2421.  
  2422. Instance variables:
  2423.     strength            the strength of this constraint <Strength>
  2424.     variables        the constrained variables <Array of DBVariable>
  2425.     methods            a collection of methods that can be used to
  2426.                     enforce this constraint <Array of Method>
  2427.     whichMethod        the method currently used to enforce this constraint
  2428.                     or nil if this constraint is not satisfied <Method>'!
  2429.  
  2430. !Constraint methodsFor: 'initialize-release'!
  2431. methods: methodList
  2432.     "Initialize myself with the given methods. I am initially not bound to variables."
  2433.  
  2434.     strength _ Strength required.
  2435.     methods _ methodList asArray.
  2436.     whichMethod _ nil.!
  2437. release
  2438.  
  2439.     strength _ nil.
  2440.     methods _ nil.
  2441.     whichMethod _ nil.!
  2442. var: variable strength: strengthSymbol
  2443.     "Install myself on the given variable with the given strength."
  2444.  
  2445.     self
  2446.         vars: (Array with: variable)
  2447.         strength: strengthSymbol!
  2448. var: variable1 var: variable2 strength: strengthSymbol
  2449.     "Install myself on the given variables with the given strength."
  2450.  
  2451.     self
  2452.         vars: (Array with: variable1 with: variable2)
  2453.         strength: strengthSymbol!
  2454. var: variable1 var: variable2 var: variable3 strength: strengthSymbol
  2455.     "Install myself on the given variables with the given strength."
  2456.  
  2457.     self
  2458.         vars: (Array with: variable1 with: variable2 with: variable3)
  2459.         strength: strengthSymbol!
  2460. var: variable1 var: variable2 var: variable3 var: variable4 strength: strengthSymbol
  2461.     "Install myself on the given variables with the given strength."
  2462.  
  2463.     self
  2464.         vars: (Array with: variable1 with: variable2 with: variable3 with: variable4)
  2465.         strength: strengthSymbol!
  2466. var: variable1 var: variable2 var: variable3 var: variable4 var: variable5 strength: strengthSymbol
  2467.     "Install myself on the given variables with the given strength."
  2468.  
  2469.     self
  2470.         vars:
  2471.             (Array with: variable1 with: variable2 with: variable3),
  2472.             (Array with: variable4 with: variable5)
  2473.         strength: strengthSymbol!
  2474. var: variable1 var: variable2 var: variable3 var: variable4 var: variable5 var: variable6 strength: strengthSymbol
  2475.     "Install myself on the given variables with the given strength."
  2476.  
  2477.     self
  2478.         vars:
  2479.             (Array with: variable1 with: variable2 with: variable3),
  2480.             (Array with: variable4 with: variable5 with: variable6)
  2481.         strength: strengthSymbol!
  2482. var: variable1 var: variable2 var: variable3 var: variable4 var: variable5 var: variable6 var: variable7 strength: strengthSymbol
  2483.     "Install myself on the given variables with the given strength."
  2484.  
  2485.     self
  2486.         vars:
  2487.             (Array with: variable1 with: variable2 with: variable3 with: variable4),
  2488.             (Array with: variable5 with: variable6 with: variable7)
  2489.         strength: strengthSymbol!
  2490. var: variable1 var: variable2 var: variable3 var: variable4 var: variable5 var: variable6 var: variable7 var: variable8 strength: strengthSymbol
  2491.     "Install myself on the given variables with the given strength."
  2492.  
  2493.     self
  2494.         vars:
  2495.             (Array with: variable1 with: variable2 with: variable3 with: variable4),
  2496.             (Array with: variable5 with: variable6 with: variable7 with: variable8)
  2497.         strength: strengthSymbol!
  2498. vars: vars strength: aSymbol
  2499.     "Install myself on the given collection of variables with the given strength."
  2500.  
  2501.     (vars size == self size) ifFalse:
  2502.         [self error: 'Wrong number of variables for this constraint.'].
  2503.     1 to: self size do:
  2504.         [: i | self at: i put: (vars at: i)].
  2505.     strength _ Strength of: aSymbol.
  2506.     self addConstraint.! !
  2507.  
  2508. !Constraint methodsFor: 'queries'!
  2509. isSatisfied
  2510.     "Answer true if this constraint is satisfied in the current solution."
  2511.  
  2512.     ^whichMethod notNil! !
  2513.  
  2514. !Constraint methodsFor: 'add/remove'!
  2515. addToGraph
  2516.     "Add myself to the constraint graph."
  2517.  
  2518.     1 to: self size do:
  2519.         [: i | (self at: i) addConstraint: self].
  2520.     whichMethod _ nil.!
  2521. removeFromGraph
  2522.     "Remove myself from the constraint graph."
  2523.  
  2524.     | v |
  2525.     1 to: self size do:
  2526.         [: i |
  2527.          v _ self at: i.
  2528.          (v == nil) ifFalse: [v removeConstraint: self]].
  2529.     whichMethod _ nil.! !
  2530.  
  2531. !Constraint methodsFor: 'planning'!
  2532. chooseMethod: mark
  2533.     "Decide if I can be satisfied and record that decision. The output of the choosen method must be not have the given mark and must have a walkabout strength less than that of this constraint."
  2534.  
  2535.     | bestOutStrength  i m mOut |
  2536.     whichMethod _ nil.
  2537.     bestOutStrength _ strength.
  2538.     i _ methods size.
  2539.     [i > 0] whileTrue:
  2540.         [m _ methods at: i.
  2541.          mOut _ self at: m outIndex.
  2542.          ((mOut mark ~= mark) &
  2543.           (mOut walkStrength weaker: bestOutStrength)) ifTrue:
  2544.             [whichMethod _ m.
  2545.              bestOutStrength _ mOut walkStrength].
  2546.          i _ i - 1].!
  2547. constantOutput
  2548.     "Answer true if:
  2549.         1. I am not an input constraint such as an EditConstraint, and
  2550.         2. If I have any inputs, they are all marked stay."
  2551.  
  2552.     | outIndex i |
  2553.     (self isInput) ifTrue: [^false].
  2554.     outIndex _ whichMethod outIndex.
  2555.     i _ self size.
  2556.     [i > 0] whileTrue:
  2557.         [(i == outIndex) ifFalse:
  2558.             [((self at: i) stay) ifFalse: [^false]].
  2559.          i _ i - 1].
  2560.     ^true!
  2561. execute
  2562.     "Enforce this constraint. Assume that it is satisfied."
  2563.  
  2564.     whichMethod execute: self.!
  2565. inputsDo: aBlock
  2566.     "See comment in AbstractConstraint."
  2567.  
  2568.     | outIndex i |
  2569.     outIndex _ whichMethod outIndex.
  2570.     i _ self size.
  2571.     [i > 0] whileTrue:
  2572.         [(i == outIndex) ifFalse:
  2573.             [aBlock value: (self at: i)].
  2574.          i _ i - 1].!
  2575. markUnsatisfied
  2576.     "Record the fact that I am unsatisfied."
  2577.  
  2578.     whichMethod _ nil.!
  2579. output
  2580.     "Answer the output variable for the currently selected method. Raise an error if the receiver is not currently satisfied."
  2581.  
  2582.     ^self at: whichMethod outIndex!
  2583. outputWalkStrength
  2584.     "Answer the walkabout strength to be assigned to the output of my selected method."
  2585.  
  2586.     | minStrength currentOutIndex i reverseOutIndex |
  2587.     minStrength _ strength.
  2588.     currentOutIndex _ whichMethod outIndex.
  2589.     i _ methods size.
  2590.     [i > 0] whileTrue:
  2591.         [reverseOutIndex _ (methods at: i) outIndex.
  2592.          (reverseOutIndex == currentOutIndex) ifFalse:
  2593.             [minStrength _
  2594.                 minStrength weakest: (self at: reverseOutIndex) walkStrength].
  2595.          i _ i - 1].
  2596.     ^minStrength!
  2597. possibleMethodsDo: aBlock
  2598.     "Evaluate the given block for all potential methods of this constraint. The block takes two arguments. The first is a list of inputs for the method. The second is the output for the method."
  2599.  
  2600.     | outIndex ins |
  2601.     methods do:
  2602.         [: m |
  2603.          outIndex _ m outIndex.
  2604.          ins _ OrderedCollection new: self size.
  2605.          1 to: self size do:
  2606.             [: i | (i == outIndex) ifFalse: [ins add: (self at: i)]].
  2607.          aBlock value: ins value: (self at: outIndex)].!
  2608. recalculate
  2609.     "Calculate the walkabout strength, the stay flag, and, if it is 'stay', the value for the current output of this constraint, and answer the current output variable. Assume this constraint is satisfied."
  2610.  
  2611.     | out stayFlag |
  2612.     out _ self at: whichMethod outIndex.
  2613.     out walkStrength: self outputWalkStrength.
  2614.     (self constantOutput)
  2615.         ifTrue:
  2616.             [out stay: true.
  2617.              self execute]     "stay optimization"
  2618.         ifFalse:
  2619.             [out stay: false].
  2620.     ^out! !
  2621.  
  2622. !ClusterSumConstraint methodsFor: 'initialize-release'!
  2623. cluster: aNodeCluster forceVar: forceVar strength: strengthSymbol
  2624.     "Initialize myself with the given variables and strength."
  2625.  
  2626.     strength _ Strength of: strengthSymbol.
  2627.     cluster _ aNodeCluster.
  2628.     output _ forceVar.
  2629.     satisfied _ false.
  2630.     self addConstraint.!
  2631. release
  2632.  
  2633.     strength _ nil.
  2634.     cluster _ nil.
  2635.     output _ nil.
  2636.     satisfied _ false.! !
  2637.  
  2638. !ClusterSumConstraint methodsFor: 'queries'!
  2639. isSatisfied
  2640.     "Answer true if this constraint is satisfied in the current solution."
  2641.  
  2642.     ^satisfied! !
  2643.  
  2644. !ClusterSumConstraint methodsFor: 'add/remove'!
  2645. addToGraph
  2646.     "Add myself to the constraint graph."
  2647.  
  2648.     self inputsDo: [: in | in addConstraint: self].
  2649.     output addConstraint: self.
  2650.     satisfied _ false.!
  2651. removeFromGraph
  2652.     "Remove myself from the constraint graph."
  2653.  
  2654.     (cluster == nil) ifFalse:
  2655.         [self inputsDo: [: in | in removeConstraint: self]].
  2656.     output removeConstraint: self.
  2657.     satisfied _ false.! !
  2658.  
  2659. !ClusterSumConstraint methodsFor: 'planning'!
  2660. chooseMethod: mark
  2661.     "Decide if I can be satisfied and record that decision."
  2662.  
  2663.     satisfied _
  2664.         (output mark ~= mark) and:
  2665.         [strength stronger: output walkStrength].!
  2666. execute
  2667.     "Enforce this constraint. Assume that it is satisfied."
  2668.  
  2669.     | forceVector thisForce |
  2670.     forceVector _ 0.0@0.0.
  2671.     cluster springs with: cluster signs do:
  2672.         [: spring : sign |
  2673.          thisForce _ sign * spring force *
  2674.             (spring p2 asFloat - spring p1 asFloat) unitVector.
  2675.          forceVector _ forceVector + thisForce].
  2676.     cluster vectors do:
  2677.         [: vector |
  2678.          thisForce _ vector p2 asFloat - vector p1 asFloat.
  2679.          forceVector _ forceVector + thisForce].
  2680.     output value: forceVector.!
  2681. inputsDo: aBlock
  2682.     "Evaluate the given block on all my current input variables."
  2683.  
  2684.     cluster springs do:
  2685.         [: spring |
  2686.          aBlock value: spring p1 xVar last.
  2687.          aBlock value: spring p1 yVar last.
  2688.          aBlock value: spring p2 xVar last.
  2689.          aBlock value: spring p2 yVar last.
  2690.          aBlock value: spring forceVar last].
  2691.     cluster vectors do:
  2692.         [: vector |
  2693.          aBlock value: vector p1 xVar last.
  2694.          aBlock value: vector p1 yVar last.
  2695.          aBlock value: vector p2 xVar last.
  2696.          aBlock value: vector p2 yVar last].!
  2697. markUnsatisfied
  2698.     "Record the fact that I am unsatisfied."
  2699.  
  2700.     satisfied _ false.!
  2701. output
  2702.     "Answer my output variable."
  2703.  
  2704.     ^output!
  2705. possibleMethodsDo: aBlock
  2706.     "Evaluate the given block for all potential methods of this constraint. The block takes two arguments. The first is a list of inputs for the method. The second is the output for the method."
  2707.  
  2708.     | ins |
  2709.     ins _ OrderedCollection new.
  2710.     self inputsDo: [: in | ins add: in].
  2711.     aBlock value: (cluster) value: output.!
  2712. recalculate
  2713.     "Cheat for now..."
  2714.  
  2715.     output walkStrength: strength.
  2716.     output stay: false.
  2717.     ^output! !
  2718.  
  2719. !TwoInOneWayConstraint methodsFor: 'initialize-release'!
  2720. release
  2721.  
  2722.     strength _ nil.
  2723.     v1 _ nil.
  2724.     v2 _ nil.
  2725.     out _ nil.
  2726.     satisfied _ false.!
  2727. var: inVar1 var: inVar2 var: outVar strength: strengthSymbol
  2728.     "Initialize myself with the given variables and strength."
  2729.  
  2730.     self initialize.
  2731.     strength _ Strength of: strengthSymbol.
  2732.     v1 _ inVar1.
  2733.     v2 _ inVar2.
  2734.     out _ outVar.
  2735.     satisfied _ false.
  2736.     self addConstraint.! !
  2737.  
  2738. !TwoInOneWayConstraint methodsFor: 'queries'!
  2739. isSatisfied
  2740.     "Answer true if this constraint is satisfied in the current solution."
  2741.  
  2742.     ^satisfied! !
  2743.  
  2744. !TwoInOneWayConstraint methodsFor: 'add/remove'!
  2745. addToGraph
  2746.     "Add myself to the constraint graph."
  2747.  
  2748.     v1 addConstraint: self.
  2749.     v2 addConstraint: self.
  2750.     out addConstraint: self.
  2751.     satisfied _ false.!
  2752. removeFromGraph
  2753.     "Remove myself from the constraint graph."
  2754.  
  2755.     (v1 == nil) ifFalse: [v1 removeConstraint: self].
  2756.     (v2 == nil) ifFalse: [v2 removeConstraint: self].
  2757.     (out == nil) ifFalse: [out removeConstraint: self].
  2758.     satisfied _ false.! !
  2759.  
  2760. !TwoInOneWayConstraint methodsFor: 'planning'!
  2761. chooseMethod: mark
  2762.     "Decide if I can be satisfied and record that decision."
  2763.  
  2764.     satisfied _
  2765.         (out mark ~= mark) and:
  2766.         [strength stronger: out walkStrength].!
  2767. execute
  2768.     "Enforce this constraint. Assume that it is satisfied."
  2769.  
  2770.     self subclassResponsibility!
  2771. inputsDo: aBlock
  2772.     "Evaluate the given block on my input variables."
  2773.  
  2774.     aBlock value: v1.
  2775.     aBlock value: v2.!
  2776. markUnsatisfied
  2777.     "Record the fact that I am unsatisfied."
  2778.  
  2779.     satisfied _ false.!
  2780. output
  2781.     "Answer my output variable."
  2782.  
  2783.     ^out!
  2784. possibleMethodsDo: aBlock
  2785.     "Evaluate the given block for all potential methods of this constraint. The block takes two arguments. The first is a list of inputs for the method. The second is the output for the method."
  2786.  
  2787.     aBlock value: (Array with: v1 with: v2) value: out.!
  2788. recalculate
  2789.     "Calculate the walkabout strength, the stay flag, and, if it is 'stay', the value for the current output of this constraint, and answer the output variable. Assume this constraint is satisfied."
  2790.  
  2791.     out walkStrength: strength.
  2792.     (v1 stay & v2 stay)
  2793.         ifTrue:
  2794.             [out stay: true.
  2795.              self execute]     "stay optimization"
  2796.         ifFalse:
  2797.             [out stay: false].
  2798.     ^out! !
  2799.  
  2800. !SetIntersectConstraint methodsFor: 'initialize-release'!
  2801. var: inSet1 var: inSet2 var: outSet strength: strengthSymbol
  2802.     "Initialize myself with the given variables and strength."
  2803.  
  2804.     strength _ Strength of: strengthSymbol.
  2805.     v1 _ inSet1.
  2806.     v2 _ inSet2.
  2807.     out _ outSet.
  2808.     satisfied _ false.
  2809.     lastS1 _ 0.
  2810.     lastS2 _ 0.
  2811.     self addConstraint.! !
  2812.  
  2813. !SetIntersectConstraint methodsFor: 'execution'!
  2814. execute
  2815.     "Enforce this constraint. Assume that it is satisfied."
  2816.  
  2817.     | s1 s2 sOut newSOut s2Elements |
  2818.     s1 _ v1 value.
  2819.     s2 _ v2 value.
  2820.     sOut _ out value.
  2821.     lastS1 _ s1
  2822.         doAdds:
  2823.             [: el |
  2824.              ((sOut includes: el) not and: [s2 includes: el]) ifTrue:
  2825.                 [sOut add: el]]
  2826.         removes:
  2827.             [: el | ((s1 includes: el) and: [s2 includes: el]) ifFalse:
  2828.                 [sOut remove: el ifAbsent: []]]
  2829.         since: lastS1
  2830.         synchBlock:
  2831.             [newSOut _ (IdentitySet new).
  2832.              s2Elements _ (IdentitySet new: (s2 size * 2)) addAll: s2; yourself.
  2833.              s1 do: [: el | (s2Elements includes: el) ifTrue: [newSOut add: el]].
  2834.              sOut newContents: newSOut].
  2835.     lastS2 _ s2
  2836.         doAdds:
  2837.             [: el |
  2838.              ((sOut includes: el) not and: [s1 includes: el]) ifTrue:
  2839.                 [sOut add: el]]
  2840.         removes:
  2841.             [: el | ((s1 includes: el) and: [s2 includes: el]) ifFalse:
  2842.                 [sOut remove: el ifAbsent: []]]
  2843.         since: lastS2
  2844.         synchBlock:
  2845.             [newSOut _ (IdentitySet new).
  2846.              s2Elements _ (IdentitySet new: (s2 size * 2)) addAll: s2; yourself.
  2847.              s1 do: [: el | (s2Elements includes: el) ifTrue: [newSOut add: el]].
  2848.               sOut newContents: newSOut].! !
  2849.  
  2850. !SetUnionConstraint methodsFor: 'initialize-release'!
  2851. var: inSet1 var: inSet2 var: outSet strength: strengthSymbol
  2852.     "Initialize myself with the given variables and strength."
  2853.  
  2854.     strength _ Strength of: strengthSymbol.
  2855.     v1 _ inSet1.
  2856.     v2 _ inSet2.
  2857.     out _ outSet.
  2858.     satisfied _ false.
  2859.     lastS1 _ 0.
  2860.     lastS2 _ 0.
  2861.     self addConstraint.! !
  2862.  
  2863. !SetUnionConstraint methodsFor: 'execution'!
  2864. execute
  2865.     "Enforce this constraint. Assume that it is satisfied."
  2866.  
  2867.     | s1 s2 sOut newSOut |
  2868.     s1 _ v1 value.
  2869.     s2 _ v2 value.
  2870.     sOut _ out value.
  2871.     lastS1 _ s1
  2872.         doAdds: [: el | (sOut includes: el) ifFalse: [sOut add: el]]
  2873.         removes:
  2874.             [: el |
  2875.              ((s1 includes: el) or: [s2 includes: el]) ifFalse:
  2876.                 [sOut remove: el ifAbsent: []]]
  2877.         since: lastS1
  2878.         synchBlock:
  2879.             [newSOut _ (IdentitySet new) addAll: s1; addAll: s2; yourself.
  2880.              sOut newContents: newSOut].
  2881.     lastS2 _ s2
  2882.         doAdds: [: el | (sOut includes: el) ifFalse: [sOut add: el]]
  2883.         removes:
  2884.             [: el |
  2885.              ((s1 includes: el) or: [s2 includes: el]) ifFalse:
  2886.                 [sOut remove: el ifAbsent: []]]
  2887.         since: lastS2
  2888.         synchBlock:
  2889.             [newSOut _ (IdentitySet new) addAll: s1; addAll: s2; yourself.
  2890.              sOut newContents: newSOut].! !
  2891.  
  2892. !SetSelectConstraint methodsFor: 'initialize-release'!
  2893. selectBlock: aBlock
  2894.     "The selection block takes two arguments: the element to select and a parameter that can be used to tune the selection criterion."
  2895.  
  2896.     selectBlock _ aBlock.
  2897.     lastSOut _ -1.    "force re-synch"!
  2898. var: inSet1 var: parameter var: outSet strength: strengthSymbol
  2899.     "Initialize myself with the given variables and strength."
  2900.  
  2901.     strength _ Strength of: strengthSymbol.
  2902.     v1 _ inSet1.
  2903.     v2 _ parameter.
  2904.     out _ outSet.
  2905.     satisfied _ false.
  2906.     lastSOut _ 0.
  2907.     lastParam _ v2 value.
  2908.     selectBlock _ [: el : param | true].    "default behavior: select all"
  2909.     self addConstraint.! !
  2910.  
  2911. !SetSelectConstraint methodsFor: 'execution'!
  2912. execute
  2913.     "Enforce this constraint. Assume that it is satisfied."
  2914.  
  2915.     | source selectionParameter sOut |
  2916.     source _ v1 value.
  2917.     selectionParameter _ v2 value.
  2918.     sOut _ out value.
  2919.     (selectionParameter ~~ lastParam) ifTrue:
  2920.         [lastSOut _ -1.    "force re-synch"
  2921.          lastParam _ selectionParameter].
  2922.     lastSOut _ source
  2923.         doAdds:
  2924.             [: el |
  2925.              ((selectBlock value: el value: selectionParameter) and:
  2926.               [(sOut includes: el) not]) ifTrue:
  2927.                 [sOut add: el]]
  2928.         removes:
  2929.             [: el |
  2930.              (sOut includes: el) ifTrue:
  2931.                  [sOut remove: el ifAbsent: []]]
  2932.         since: lastSOut
  2933.         synchBlock:
  2934.             [sOut copy do:
  2935.                 [: el |
  2936.                  ((selectBlock value: el value: selectionParameter) not or:
  2937.                    [(source includes: el) not]) ifTrue:
  2938.                     [sOut remove: el]].
  2939.              source do:
  2940.                 [: el |
  2941.                  ((selectBlock value: el value: selectionParameter) and:
  2942.                    [(sOut includes: el) not]) ifTrue:
  2943.                     [sOut add: el]]].! !
  2944.  
  2945. !UnaryConstraint methodsFor: 'initialize-release'!
  2946. release
  2947.  
  2948.     strength _ nil.
  2949.     output _ nil.
  2950.     satisfied _ nil.!
  2951. var: aVariable primstrength: s
  2952.     strength _ s.
  2953.     output _ aVariable.
  2954.     satisfied _ false.
  2955.     self addConstraint.!
  2956. var: aVariable strength: strengthSymbol
  2957.     "Initialize myself with the given variable and strength."
  2958.  
  2959.     strength _ Strength of: strengthSymbol.
  2960.     output _ aVariable.
  2961.     satisfied _ false.
  2962.     self addConstraint.! !
  2963.  
  2964. !UnaryConstraint methodsFor: 'queries'!
  2965. isSatisfied
  2966.     "Answer true if this constraint is satisfied in the current solution."
  2967.  
  2968.     ^satisfied! !
  2969.  
  2970. !UnaryConstraint methodsFor: 'add/remove'!
  2971. addToGraph
  2972.     "Add myself to the constraint graph."
  2973.  
  2974.     output addConstraint: self.
  2975.     satisfied _ false.!
  2976. removeFromGraph
  2977.     "Remove myself from the constraint graph."
  2978.  
  2979.     (output == nil) ifFalse: [output removeConstraint: self].
  2980.     satisfied _ false.! !
  2981.  
  2982. !UnaryConstraint methodsFor: 'planning'!
  2983. chooseMethod: mark
  2984.     "Decide if I can be satisfied and record that decision."
  2985.  
  2986.     satisfied _
  2987.         (output mark ~= mark) and:
  2988.         [strength stronger: output walkStrength].!
  2989. execute
  2990.     "Enforce this constraint. Assume that it is satisfied."
  2991.  
  2992.     self subclassResponsibility!
  2993. inputsDo: aBlock
  2994.     "I have no input variables."!
  2995. markUnsatisfied
  2996.     "Record the fact that I am unsatisfied."
  2997.  
  2998.     satisfied _ false.!
  2999. output
  3000.     "Answer my current output variable."
  3001.  
  3002.     ^output!
  3003. possibleMethodsDo: aBlock
  3004.     "Evaluate the given block for all potential methods of this constraint. The block takes two arguments. The first is a list of inputs for the method. The second is the output for the method."
  3005.  
  3006.     aBlock value: #() value: output.!
  3007. recalculate
  3008.     "Calculate the walkabout strength, the stay flag, and, if it is 'stay', the value for the current output of this constraint, and answer the output variable. Assume this constraint is satisfied."
  3009.  
  3010.     output walkStrength: strength.
  3011.     (self isInput)
  3012.         ifTrue:
  3013.             [output stay: false]
  3014.         ifFalse:
  3015.             [output stay: true.
  3016.              self execute].     "stay optimization"
  3017.     ^output! !
  3018.  
  3019. StayConstraint comment:
  3020. 'I mark variables that should, with some level of preference, stay the same. I have one method with zero inputs and one output, which does nothing. Planners may exploit the fact that, if I am satisfied, my output will not change during plan execution. This is called "stay optimization."'!
  3021.  
  3022. !StayConstraint methodsFor: 'queries'!
  3023. includeInPlan
  3024.     "Stay constraints have no effect other than to control the planning process."
  3025.  
  3026.     ^false! !
  3027.  
  3028. !StayConstraint methodsFor: 'execution'!
  3029. codeStringFor: vars on: aStream
  3030.     "Stay constraints do nothing."!
  3031. execute
  3032.     "Stay constraints do nothing."! !
  3033.  
  3034. EditConstraint comment:
  3035. 'I am used to mark a variable that the user wishes to edit. I have one method with zero inputs and one output, which does nothing.'!
  3036.  
  3037. !EditConstraint methodsFor: 'queries'!
  3038. includeInPlan
  3039.     "Edit constraints have no effect other than to control the planning process."
  3040.  
  3041.     ^false!
  3042. isInput
  3043.     "I indicate that a variable is to be changed by imperative code."
  3044.  
  3045.     ^true! !
  3046.  
  3047. !EditConstraint methodsFor: 'execution'!
  3048. codeStringFor: vars on: aStream
  3049.     "Edit constraints do nothing."!
  3050. execute
  3051.     "Edit constraints do nothing."! !
  3052.  
  3053. XMouseConstraint comment:
  3054. 'I am an input constraint that relates a variable to the current x-coordinate of the mouse. I contain an offset to normalize the coordinate system to one convenient for the target variable. I have one method with zero inputs and one output.'!
  3055.  
  3056. !XMouseConstraint methodsFor: 'initialize-release'!
  3057. var: aVariable strength: strengthSymbol offset: aNumber
  3058.     "Install myself with the given variable, strength, and x-offset."
  3059.  
  3060.     xOffset _ aNumber.
  3061.     self var: aVariable strength: strengthSymbol.! !
  3062.  
  3063. !XMouseConstraint methodsFor: 'queries'!
  3064. isInput
  3065.     "I depend on the state of the mouse."
  3066.  
  3067.     ^true! !
  3068.  
  3069. !XMouseConstraint methodsFor: 'execution'!
  3070. codeStringFor: vars on: aStream
  3071.  
  3072.     aStream tab.
  3073.     aStream nextPutAll: (vars at: output).
  3074.     aStream nextPutAll: ' value: (Sensor mousePoint x + ', xOffset printString, ').'.
  3075.     aStream cr.!
  3076. execute
  3077.     "Enforce this constraint. Assume that it is satisfied."
  3078.  
  3079.     output value: (Sensor mousePoint x + xOffset).! !
  3080.  
  3081. YMouseConstraint comment:
  3082. 'I am an input constraint that relates a variable to the current y-coordinate of the mouse. I contain an offset to normalize the coordinate system to one convenient for the target variable. I have one method with zero inputs and one output.'!
  3083.  
  3084. !YMouseConstraint methodsFor: 'initialize-release'!
  3085. var: aVariable strength: strengthSymbol offset: aNumber
  3086.     "Install myself with the given variable, strength, and y-offset."
  3087.  
  3088.     yOffset _ aNumber.
  3089.     self var: aVariable strength: strengthSymbol.! !
  3090.  
  3091. !YMouseConstraint methodsFor: 'queries'!
  3092. isInput
  3093.     "I depend on the state of the mouse."
  3094.  
  3095.     ^true! !
  3096.  
  3097. !YMouseConstraint methodsFor: 'execution'!
  3098. codeStringFor: vars on: aStream
  3099.  
  3100.     aStream tab.
  3101.     aStream nextPutAll: (vars at: output).
  3102.     aStream nextPutAll: ' value: (Sensor mousePoint y + ', yOffset printString, ').'.
  3103.     aStream cr.!
  3104. execute
  3105.     "Enforce this constraint. Assume that it is satisfied."
  3106.  
  3107.     output value: (Sensor mousePoint y + yOffset).! !
  3108.  
  3109. !BinaryConstraint methodsFor: 'initialize-release'!
  3110. bind: vars strength: aSymbol
  3111.     "Bind myself to the given variables with the given strength but do not yet attempt to satisfy myself."
  3112.  
  3113.     (vars size == 2) ifFalse: [self error: 'Wrong number of variables'].
  3114.     strength _ Strength of: aSymbol.
  3115.     v1 _ vars first.
  3116.     v2 _ vars last.
  3117.     direction _ nil.!
  3118. release
  3119.  
  3120.     strength _ nil.
  3121.     v1 _ nil.
  3122.     v2 _ nil.
  3123.     direction _ nil.!
  3124. var: variable1 var: variable2 strength: strengthSymbol
  3125.     "Initialize myself with the given variables and strength."
  3126.  
  3127.     strength _ Strength of: strengthSymbol.
  3128.     v1 _ variable1.
  3129.     v2 _ variable2.
  3130.     direction _ nil.
  3131.     ((v1 notNil) & (v2 notNil)) ifTrue:
  3132.         [self addConstraint].! !
  3133.  
  3134. !BinaryConstraint methodsFor: 'queries'!
  3135. isSatisfied
  3136.     "Answer true if this constraint is satisfied in the current solution."
  3137.  
  3138.     ^direction notNil! !
  3139.  
  3140. !BinaryConstraint methodsFor: 'add/remove'!
  3141. addToGraph
  3142.     "Add myself to the constraint graph."
  3143.  
  3144.     v1 addConstraint: self.
  3145.     v2 addConstraint: self.
  3146.     direction _ nil.!
  3147. removeFromGraph
  3148.     "Remove myself from the constraint graph."
  3149.  
  3150.     (v1 == nil) ifFalse: [v1 removeConstraint: self].
  3151.     (v2 == nil) ifFalse: [v2 removeConstraint: self].
  3152.     direction _ nil.! !
  3153.  
  3154. !BinaryConstraint methodsFor: 'planning'!
  3155. chooseMethod: mark
  3156.     "Decide which way I should flow based on the relative strength of the variables I relate and record that decision."
  3157.  
  3158.     (v1 mark == mark) ifTrue:        "forward or nothing"
  3159.         [((v2 mark ~= mark) and: [strength stronger: v2 walkStrength])
  3160.             ifTrue: [^direction _ #forward]
  3161.             ifFalse: [^direction _ nil]].
  3162.  
  3163.     (v2 mark == mark) ifTrue:        "backward or nothing"
  3164.         [((v1 mark ~= mark) and: [strength stronger: v1 walkStrength])
  3165.             ifTrue: [^direction _ #backward]
  3166.             ifFalse: [^direction _ nil]].
  3167.  
  3168.     "if we get here, neither variable is marked, so we have choice"
  3169.     (v1 walkStrength weaker: v2 walkStrength)
  3170.         ifTrue:
  3171.             [(strength stronger: v1 walkStrength)
  3172.                 ifTrue: [^direction _ #backward]
  3173.                 ifFalse: [^direction _ nil]]
  3174.         ifFalse:
  3175.             [(strength stronger: v2 walkStrength)
  3176.                 ifTrue: [^direction _ #forward]
  3177.                 ifFalse: [^direction _ nil]].!
  3178. execute
  3179.     "Enforce this constraint. Assume that it is satisfied."
  3180.  
  3181.     self subclassResponsibility!
  3182. inputsDo: aBlock
  3183.     "Evaluate the given block on my current input variable."
  3184.  
  3185.     (direction == #forward)
  3186.         ifTrue: [aBlock value: v1]
  3187.         ifFalse: [aBlock value: v2].!
  3188. markUnsatisfied
  3189.     "Record the fact that I am unsatisfied."
  3190.  
  3191.     direction _ nil.!
  3192. output
  3193.     "Answer my current output variable."
  3194.  
  3195.     (direction == #forward)
  3196.         ifTrue: [^v2]
  3197.         ifFalse: [^v1]!
  3198. possibleMethodsDo: aBlock
  3199.     "Evaluate the given block for all potential methods of this constraint. The block takes two arguments. The first is a list of inputs for the method. The second is the output for the method."
  3200.  
  3201.     aBlock value: (Array with: v1) value: v2.
  3202.     aBlock value: (Array with: v2) value: v1.!
  3203. recalculate
  3204.     "Calculate the walkabout strength, the stay flag, and, if it is 'stay', the value for the current output of this constraint, and answer the output variable. Assume this constraint is satisfied."
  3205.  
  3206.     | in out |
  3207.     (direction == #forward)
  3208.         ifTrue: [in _ v1. out _ v2]
  3209.         ifFalse: [out _ v1. in _ v2].
  3210.     out walkStrength: (strength weakest: in walkStrength).
  3211.     (in stay)
  3212.         ifTrue:
  3213.             [out stay: true.
  3214.              self execute]     "stay optimization"
  3215.         ifFalse:
  3216.             [out stay: false].
  3217.     ^out! !
  3218.  
  3219. OffsetConstraint comment:
  3220. 'I relate two variables by a fixed offset: "v1 + offset = v2".'!
  3221.  
  3222. !OffsetConstraint methodsFor: 'initialize-release'!
  3223. from: variable1 to: variable2 strength: strengthSymbol offset: aNumber
  3224.  
  3225.     offset _ aNumber.
  3226.     self var: variable1 var: variable2 strength: strengthSymbol.! !
  3227.  
  3228. !OffsetConstraint methodsFor: 'execution'!
  3229. codeStringFor: vars on: aStream
  3230.  
  3231.     aStream tab.
  3232.     (direction == #forward)
  3233.         ifTrue: [aStream nextPutAll: (vars at: v2), ' value: ', (vars at: v1), ' value + ']
  3234.         ifFalse: [aStream nextPutAll: (vars at: v1), ' value: ', (vars at: v2), ' value - '].
  3235.     aStream nextPutAll: offset printString, ').'.
  3236.     aStream cr.!
  3237. execute
  3238.     "Enforce this constraint. Assume that it is satisfied."
  3239.  
  3240.     (direction == #forward)
  3241.         ifTrue: [v2 value: (v1 value + offset)]
  3242.         ifFalse: [v1 value: (v2 value - offset)].! !
  3243.  
  3244. !BijectiveMapConstraint methodsFor: 'initialize-release'!
  3245. fromSet: fromSet toSet: toSet fromClass: fromC toClass: toC strength: strengthSymbol 
  3246.  
  3247.     fromClass _ fromC.
  3248.     toClass _ toC.
  3249.     pairConstraints _ OrderedCollection new.
  3250.     map _ IdentityDictionary new: 400.
  3251.     lastUpdate _ 0.
  3252.     self var: fromSet var: toSet strength: strengthSymbol.!
  3253. release
  3254.  
  3255.     super release.
  3256.     fromClass _ nil.
  3257.     toClass _ nil.
  3258.     pairConstraints _ nil.
  3259.     map _ nil.
  3260.     lastUpdate _ nil.! !
  3261.  
  3262. !BijectiveMapConstraint methodsFor: 'pairwise add/remove'!
  3263. addPairwiseConstraint: aPairConstraint
  3264.     "Incrementally add the given pairwise constraint between my sets."
  3265.  
  3266.     | entries pairC |
  3267.     pairConstraints add: aPairConstraint.
  3268.     entries _ IdentitySet new: (map size * 4).
  3269.     map do: [: entry | entries add: entry].
  3270.     entries do:
  3271.         [: entry |
  3272.          pairC _ aPairConstraint constraintFrom: (entry at: 1) to: (entry at: 2).
  3273.          (entry at: 3) add: pairC].!
  3274. removePairwiseConstraint: aPairConstraint
  3275.     "Remove the given pairwise constraint from my sets. This operation is expensive."
  3276.  
  3277.     pairConstraints remove: aPairConstraint ifAbsent: [].
  3278.     self resynch.! !
  3279.  
  3280. !BijectiveMapConstraint methodsFor: 'pairwise constraints'!
  3281. equate: pathInSourceObject with: pathInDestinationObject strength: strengthSymbol
  3282.     "Set the given parts of the objects in the destination set equal to the corresponding parts of the objects in the source set."
  3283.  
  3284.     self addPairwiseConstraint:
  3285.         ((PairConstraintHolder new)
  3286.             constraint:
  3287.                 (EqualityConstraint var: nil var: nil strength: strengthSymbol)
  3288.             fromPath: pathInSourceObject
  3289.             toPath: pathInDestinationObject
  3290.             strength: strengthSymbol).!
  3291. offset: pathInDestinationObject from: pathInSourceObject by: offset strength: strengthSymbol
  3292.     "Offset the given parts of the objects in the destination set by a fixed amount from the corresponding parts of the objects in the source set."
  3293.  
  3294.     self addPairwiseConstraint:
  3295.         ((PairConstraintHolder new)
  3296.             constraint:
  3297.                 (OffsetConstraint from: nil to: nil strength: strengthSymbol offset: offset)
  3298.             fromPath: pathInSourceObject
  3299.             toPath: pathInDestinationObject
  3300.             strength: strengthSymbol).!
  3301. require: pathInSourceObject equals: pathInDestinationObject
  3302.     "Set the given parts of the objects in the destination set equal to the corresponding parts of the objects in the source set."
  3303.  
  3304.     self addPairwiseConstraint:
  3305.         ((PairConstraintHolder new)
  3306.             constraint:
  3307.                 (EqualityConstraint var: nil var: nil strength: #required)
  3308.             fromPath: pathInSourceObject
  3309.             toPath: pathInDestinationObject
  3310.             strength: #required).! !
  3311.  
  3312. !BijectiveMapConstraint methodsFor: 'execution'!
  3313. add: newItem
  3314.     "Create an image of the new item in the image set, and constraint the pair (newItem, image) with my pairwise constraints."
  3315.  
  3316.     | src dest entry pairC |
  3317.     (map includesKey: newItem) ifTrue: [^self].     "already there"
  3318.     (direction == #forward)
  3319.         ifTrue:
  3320.             [src _ newItem.
  3321.              dest _ toClass new.
  3322.              v2 value add: dest]
  3323.         ifFalse:
  3324.             [src _ fromClass new.
  3325.              dest _ newItem.
  3326.              v1 value add: src].
  3327.  
  3328.     entry _ Array with: src with: dest with: OrderedCollection new.
  3329.     pairConstraints do:
  3330.         [: mapC |
  3331.          pairC _ mapC constraintFrom: src to: dest.
  3332.          (entry at: 3) add: pairC].
  3333.     map at: src put: entry.
  3334.     map at: dest put: entry.!
  3335. execute
  3336.     "Enforce this constraint. This is done by incrementally updating the current output set."
  3337.  
  3338.     | in |
  3339.     in _ (direction == #forward) ifTrue: [v1] ifFalse: [v2].
  3340.     lastUpdate _ (in value)
  3341.         doAdds: [: el | self add: el]
  3342.         removes: [: el | self remove: el]
  3343.         since: lastUpdate
  3344.         synchBlock: [self resynch].!
  3345. remove: oldItem
  3346.     "Delete the given item from my map and image set and remove all pairwise constraints on the item."
  3347.  
  3348.     | entry |
  3349.     entry _ (map at: oldItem ifAbsent: [^self]).    "already removed"
  3350.     ((entry at: 1) == oldItem)
  3351.         ifTrue: [v2 value remove: (entry at: 2)]
  3352.         ifFalse: [v1 value remove: (entry at: 2)].
  3353.     (entry at: 3) do:
  3354.         [: pairC | pairC destroyConstraint].
  3355.     map removeKey: (entry at: 1) ifAbsent: [].
  3356.     map removeKey: (entry at: 2) ifAbsent: [].!
  3357. resynch
  3358.     "Reconstruct the output set from scratch. This operation is very expensive."
  3359.  
  3360.     | in out pairwiseConstraints |
  3361.     (direction == #forward)
  3362.         ifTrue: [in _ v1. out _ v2]
  3363.         ifFalse: [out _ v1. in _ v2].
  3364.  
  3365.     "remove all pairwise constraints"
  3366.     pairwiseConstraints _ IdentitySet new: (map size * 4).
  3367.     map do:
  3368.         [: entry |
  3369.          pairwiseConstraints addAll: (entry at: 3)].
  3370.     pairwiseConstraints do: [: c | c destroyConstraint].
  3371.  
  3372.     "clear map and output set, then reconstruct the output set"
  3373.     map _ IdentityDictionary new: 400.
  3374.     (out value) removeAll.
  3375.     (in value) do: [: el | self add: el].! !
  3376.  
  3377. EqualityConstraint comment:
  3378. 'I constrain two variables to have the same value: "v1 = v2".'!
  3379.  
  3380. !EqualityConstraint methodsFor: 'execution'!
  3381. codeStringFor: vars on: aStream
  3382.  
  3383.     aStream tab.
  3384.     (direction == #forward)
  3385.         ifTrue: [aStream nextPutAll: (vars at: v2), ' value: ', (vars at: v1), ' value.']
  3386.         ifFalse: [aStream nextPutAll: (vars at: v1), ' value: ', (vars at: v2), ' value.'].
  3387.     aStream cr.!
  3388. execute
  3389.     "Enforce this constraint. Assume that it is satisfied."
  3390.  
  3391.     (direction == #forward)
  3392.         ifTrue: [v2 value: v1 value]
  3393.         ifFalse: [v1 value: v2 value].! !
  3394.  
  3395. !MergeConstraint methodsFor: 'queries'!
  3396. isMergeConstraint
  3397.     "I am a merge constraint. Merge constraints are simply equality constraints used to merge parts."
  3398.  
  3399.     ^true! !
  3400.  
  3401. !UserEqualityConstraint methodsFor: 'queries'!
  3402. isUserConstraint
  3403.     "I am a user-added constraint."
  3404.  
  3405.     ^true! !
  3406.  
  3407. !LayoutConstraint methodsFor: 'queries'!
  3408. isLayoutConstraint
  3409.  
  3410.     ^true! !
  3411.  
  3412. !ScaleConstraint methodsFor: 'initialize-release'!
  3413. release
  3414.  
  3415.     super release.
  3416.     scale _ nil.
  3417.     offset _ nil.!
  3418. src: srcVar scale: scaleVar offset: offsetVar dst: dstVar strength: strengthSymbol
  3419.     "Initialize myself with the given variables and strength."
  3420.  
  3421.     strength _ Strength of: strengthSymbol.
  3422.     v1 _ srcVar.
  3423.     v2 _ dstVar.
  3424.     scale _ scaleVar.
  3425.     offset _ offsetVar.
  3426.     direction _ nil.
  3427.     ((v1 notNil) & (v2 notNil)& (scale notNil)& (offset notNil)) ifTrue:
  3428.         [self addConstraint].! !
  3429.  
  3430. !ScaleConstraint methodsFor: 'add/remove'!
  3431. addToGraph
  3432.     "Add myself to the constraint graph."
  3433.  
  3434.     v1 addConstraint: self.
  3435.     v2 addConstraint: self.
  3436.     scale addConstraint: self.
  3437.     offset addConstraint: self.
  3438.     direction _ nil.!
  3439. removeFromGraph
  3440.     "Remove myself from the constraint graph."
  3441.  
  3442.     (v1 == nil) ifFalse: [v1 removeConstraint: self].
  3443.     (v2 == nil) ifFalse: [v2 removeConstraint: self].
  3444.     (scale == nil) ifFalse: [scale removeConstraint: self].
  3445.     (offset == nil) ifFalse: [offset removeConstraint: self].
  3446.     direction _ nil.! !
  3447.  
  3448. !ScaleConstraint methodsFor: 'planning'!
  3449. execute
  3450.     "Enforce this constraint. Assume that it is satisfied."
  3451.  
  3452.     (direction == #forward)
  3453.         ifTrue: [v2 value: (v1 value * scale value) + offset value]
  3454.         ifFalse: [v1 value: (v2 value - offset value) // scale value].!
  3455. inputsDo: aBlock
  3456.     "Evaluate the given block on my current input variable."
  3457.  
  3458.     (direction == #forward)
  3459.         ifTrue: [aBlock value: v1; value: scale; value: offset]
  3460.         ifFalse: [aBlock value: v2; value: scale; value: offset].!
  3461. possibleMethodsDo: aBlock
  3462.     "Evaluate the given block for all potential methods of this constraint. The block takes two arguments. The first is a list of inputs for the method. The second is the output for the method."
  3463.  
  3464.     aBlock value: (Array with: v1 with: scale with: offset) value: v2.
  3465.     aBlock value: (Array with: v2 with: scale with: offset) value: v1.!
  3466. recalculate
  3467.     "Calculate the walkabout strength, the stay flag, and, if it is 'stay', the value for the current output of this constraint, and answer the output variable. Assume this constraint is satisfied."
  3468.  
  3469.     | in out |
  3470.     (direction == #forward)
  3471.         ifTrue: [in _ v1. out _ v2]
  3472.         ifFalse: [out _ v1. in _ v2].
  3473.     out walkStrength: (strength weakest: in walkStrength).
  3474.     ((in stay) and: [(scale stay) and: [offset stay]])
  3475.         ifTrue:
  3476.             [out stay: true.
  3477.              self execute]     "stay optimization"
  3478.         ifFalse:
  3479.             [out stay: false].
  3480.     ^out! !
  3481.  
  3482. AdagioParser comment:
  3483. 'I am a parser for the Adagio score representation language as described in the CMU Midi Toolkit handbook. I am  invoked by "AdagioParser parse: stream" where the stream typically comes from a string or file. I am driven by a table of token types, TypeTable. (This table is defined in my class initialization message.) I work by collecting note attributes and flags until a delimiter is reached, at which point I output a note and update the current time according to the current set of attributes. Delimiters are comma, semi-colon, and the end of a line. Please see the description of the Adagio language in the CMU Midi Toolkit handbook for further details.'!
  3484.  
  3485. !AdagioParser methodsFor: 'initialize-release'!
  3486. initAdagioDefaults
  3487.     "Initialize all Adagio state variables to their default values."
  3488.  
  3489.     tempo _ 100.0.
  3490.     rate _ 100.0.
  3491.     synchPoint _ 0.0.
  3492.     time _ 0.0.
  3493.     duration _ DurationsTable at: $q.
  3494.     nextTimeDelta _ nil.
  3495.     pitchClass _ PitchTable at: $c.
  3496.     modifier _ 0.
  3497.     octave _ 4.
  3498.     loudness _ 127.
  3499.     voice _ 1.
  3500.     timbre _ 1.
  3501.     restFlag _ false.
  3502.     hadAttributeFlag _ false.!
  3503. parse: aStream
  3504.     "Parse the Adagio score in aStream and answer the resulting Score object."
  3505.  
  3506.     typeTable _ AdagioTypeTable.
  3507.     source _ aStream.
  3508.     buffer _ BufferStream on: (String new: 40).
  3509.     self nextChar.    "prime the pump"
  3510.     notes _ MergeSorter new.
  3511.     self initAdagioDefaults.
  3512.     [self doNext] whileFalse: [].    "parse until done"
  3513.     ^notes asScore! !
  3514.  
  3515. !AdagioParser methodsFor: 'attribute parsing'!
  3516. parseDur
  3517.     "Parse the symbolic duration contained in buffer (e.g. 'q.t' is a dotted quarter triplet). Answer the duration in 100ths of a second if this succeeds, answer nil if it fails."
  3518.  
  3519.     | dur ch multiplier |
  3520.     dur _ DurationsTable
  3521.             at: buffer next
  3522.             ifAbsent:
  3523.                 [self badAttribute: buffer contents.
  3524.                 ^nil].
  3525.  
  3526.     [(buffer atEnd not) and: [buffer peek isDigit not]]
  3527.         whileTrue: [
  3528.             ch _ buffer next.
  3529.             (ch == $.) ifTrue: [dur _ dur * 1.5].
  3530.             (ch == $t) ifTrue: [dur _ dur * 0.66666666].
  3531.             ((ch == $t) | (ch == $.)) ifFalse:
  3532.                 [self badAttribute: buffer contents.
  3533.                  ^nil]].        "bad attribute; abort"
  3534.  
  3535.     (buffer atEnd)
  3536.         ifTrue: [^dur]
  3537.         ifFalse:
  3538.             [multiplier _ self convertToNumber: buffer posOnly: true.
  3539.              multiplier isNil ifTrue: [^nil].    "bad number; abort"
  3540.              ^dur * multiplier].!
  3541. parsePitchModifier
  3542.     "Parse a pitch modifer. Answer nil if it is bad."
  3543.  
  3544.     | ch |
  3545.     ch _ buffer next.
  3546.     (ch == $s)
  3547.         ifTrue:
  3548.             ["sharp"
  3549.              modifier notNil ifTrue: [^nil].
  3550.              ^modifier _ 1].
  3551.     (ch == $f)
  3552.         ifTrue:
  3553.             ["flat"
  3554.              modifier notNil ifTrue: [^nil].
  3555.              ^modifier _ -1].
  3556.     (ch == $n)
  3557.         ifTrue:
  3558.             ["natural"
  3559.              modifier notNil ifTrue: [^nil].
  3560.              ^modifier _ 0].
  3561.     (ch isDigit)
  3562.         ifTrue:
  3563.             [octave notNil ifTrue: [^nil].
  3564.              ^octave _ ch digitValue].
  3565.     (ch == $- and: [(ch _ buffer next) isDigit])
  3566.         ifTrue:
  3567.             [octave notNil ifTrue: [^nil].
  3568.              ^octave _ ch digitValue negated].
  3569.  
  3570.     "if we get here, we have encountered a bad pitch modifer"
  3571.     ^nil!
  3572. parseRate
  3573.     "Parse an Adagio rate command (e.g. '!!rate 120')."
  3574.  
  3575.     | newRate |
  3576.     self skipWhiteSpace.
  3577.     self scanAttribute.
  3578.     newRate _ self convertToNumber: buffer posOnly: true.
  3579.     newRate isNil
  3580.         ifTrue: [
  3581.             "bad number; abort"
  3582.             ^self error: 'bad argument to !!rate', self token].
  3583.     rate _ newRate asFloat.
  3584.     synchPoint _ time.
  3585.     notes startNewSublist.
  3586.     self specialCheck.!
  3587. parseTempo
  3588.     "Parses an Adagio tempo command (e.g. '!!tempo 120')."
  3589.  
  3590.     | newTempo |
  3591.     self skipWhiteSpace.
  3592.     self scanAttribute.
  3593.     newTempo _ self convertToNumber: buffer posOnly: true.
  3594.     newTempo isNil
  3595.         ifTrue: [
  3596.             "bad number; abort"
  3597.             ^self error: 'bad argument to !!tempo', self token].
  3598.     tempo _ newTempo asFloat.
  3599.     synchPoint _ time.
  3600.     notes startNewSublist.
  3601.     self specialCheck.!
  3602. xAbsDuration
  3603.     "Parses absolute durations (e.g. 'u60' is a note lasting 60 100ths of a second)."
  3604.  
  3605.     | dur |
  3606.     self scanAttribute.
  3607.     buffer next.
  3608.     (buffer atEnd) ifTrue: [^self badAttribute].
  3609.     dur _ self convertToNumber: buffer posOnly: true.
  3610.     dur isNil
  3611.         ifTrue: [^self].    "bad number; abort"
  3612.     duration _ dur asFloat * (tempo / 100.0).        "scale to current tempo."
  3613.     hadAttributeFlag _ true.!
  3614. xAbsPitch
  3615.     "Parses absolute pitches (e.g. 'p48' is middle C). NOTE: Adagio pitch numbering (middle C = 48) differs from Midi pitch numbering (middle C = 60). Be warned."
  3616.  
  3617.     | p |
  3618.     self scanAttribute.
  3619.     buffer next.
  3620.     (buffer atEnd) ifTrue: [^self badAttribute].
  3621.     p _ self convertToNumber: buffer posOnly: false.
  3622.     (p isNil) ifTrue: [^self].    "bad number; abort"
  3623.     (p < -12) ifTrue:
  3624.         [self range: 'pitch' value: p using: -12.
  3625.          p _ -12].
  3626.     (p > 115) ifTrue:
  3627.         [self range: 'pitch' value: p using: 115.
  3628.          p _ 115].
  3629.     pitchClass _ p \\ 12.
  3630.     modifier _ 0.
  3631.     octave _ p // 12.
  3632.     hadAttributeFlag _ true.!
  3633. xComment
  3634.     "A comment starts with a '*' character and runs through the end of the line."
  3635.  
  3636.     self skipRestOfLine.!
  3637. xDuration
  3638.     "Parses symbolic durations (e.g. 'q.t' is a dotted quarter triplet)."
  3639.  
  3640.     | dur |
  3641.     self scanAttribute.
  3642.     dur _ self parseDur.
  3643.     dur isNil
  3644.         ifTrue: [^self].        "bad attribute; abort"
  3645.     duration _ dur.
  3646.     hadAttributeFlag _ true.!
  3647. xLoudness
  3648.     "Parses loudness attributes, either absolute or symbolic (e.g. 'L58' = 'Lmf', both of which  mean to play with a loudness of mezzo forte)."
  3649.  
  3650.     | stream loud |
  3651.     self scanAttribute.
  3652.     buffer next.
  3653.     (buffer atEnd) ifTrue: [^self badAttribute].
  3654.     (buffer peek isDigit)
  3655.         ifTrue:
  3656.             [loud _ self convertToNumber: buffer posOnly: true.
  3657.              loud isNil ifTrue: [^self].    "bad number; abort"
  3658.              (loud > 127)
  3659.                 ifTrue:
  3660.                     [self range: 'loudness' value: loud using: 127.
  3661.                      loud _ 127].
  3662.              (loud < 1)
  3663.                 ifTrue:
  3664.                     [self range: 'loudness' value: loud using: 1.
  3665.                      loud _ 1]]
  3666.         ifFalse:
  3667.             [loud _ DynamicsTable
  3668.                         at: buffer throughEnd asSymbol
  3669.                         ifAbsent: [^self badAttribute]].
  3670.     loudness _ loud.
  3671.     hadAttributeFlag _ true.!
  3672. xNextTime
  3673.     "Parses a next time attribute. The next time value may be a positive number or it may be a symbolic duration. For example, 'n60' = 'nq' at a tempo of 100; both cause the next note to be played a quarter note amount of time after the current note, or 60/100ths of a second."
  3674.  
  3675.     | n |
  3676.     self scanAttribute.
  3677.     buffer next.
  3678.     (buffer atEnd) ifTrue: [^self badAttribute].
  3679.     (buffer peek isDigit)
  3680.         ifTrue:
  3681.             [n _ (self convertToNumber: buffer posOnly: true) * (100.0 / rate).
  3682.              n isNil ifTrue: [^self]]    "bad number; abort"
  3683.         ifFalse:
  3684.             [n _ (self parseDur) * (100.0 / tempo) * (100.0 / rate).
  3685.              n isNil ifTrue: [^self]].    "bad duration; abort"
  3686.     nextTimeDelta _ n.
  3687.     hadAttributeFlag _ true.!
  3688. xPitch
  3689.     "Parses a pitch attribute starting with a pitch name. See xAbsPitch for absolute pitch parsing."
  3690.  
  3691.     | oldPitchClass oldModifier oldOctave oldPClass newPClass pitchDif |
  3692.     self scanAttribute.
  3693.     oldPitchClass _ pitchClass.
  3694.     oldModifier _ modifier.
  3695.     oldOctave _ octave.
  3696.     pitchClass _ PitchTable at: (buffer next) ifAbsent: [^self badAttribute].
  3697.     modifier _ octave _ nil.
  3698.     [buffer atEnd]
  3699.         whileFalse:
  3700.             ["process pitch modifiers: octave, sharp, flat and natural"
  3701.              (self parsePitchModifier isNil)
  3702.                 ifTrue:
  3703.                     ["nil indicates a bad pitch modifier"
  3704.                      pitchClass _ oldPitchClass.
  3705.                      modifier _ oldModifier.
  3706.                      octave _ oldOctave.
  3707.                      ^self badAttribute]].
  3708.     hadAttributeFlag _ true.
  3709.     modifier isNil ifTrue: [modifier _ 0].    "no modifier specified"
  3710.     (octave isNil)
  3711.         ifTrue:
  3712.             ["if no octave was specified, use the one which minimizes the leap from the previous note"
  3713.              oldPClass _ (oldPitchClass + oldModifier) \\ 12.
  3714.              newPClass _ (pitchClass + modifier) \\ 12.
  3715.              pitchDif _ newPClass - oldPClass.    "compare with last pitch"
  3716.              (pitchDif > 5)
  3717.                 ifTrue: [^octave _ oldOctave - 1 max: -1].
  3718.              (pitchDif < -6)
  3719.                 ifTrue: [^octave _ oldOctave + 1 min: 9].
  3720.             octave _ oldOctave].!
  3721. xProgram
  3722.     "Parses a program number attribute (e.g. 'z48' sets the synthesizer to timber 48)."
  3723.  
  3724.     | prog |
  3725.     self scanAttribute.
  3726.     buffer next.
  3727.     (buffer atEnd) ifTrue: [^self badAttribute].
  3728.     prog _ self convertToNumber: buffer posOnly: true.
  3729.     (prog isNil)
  3730.         ifTrue: [^self].    "bad number; abort"
  3731.     (prog < 1)
  3732.         ifTrue:
  3733.             [self range: 'program number' value: prog using: 1.
  3734.              prog _ 1].
  3735.     (prog > 127)
  3736.         ifTrue:
  3737.             [self range: 'program number' value: prog using: 127.
  3738.              prog _ 127].
  3739.     timbre _ prog.
  3740.     hadAttributeFlag _ true.!
  3741. xRest
  3742.     "Sets a flag indicating that this was a rest. This flag suppresses generation of a note, although other attributes such as voice, timbre, and time are updated."
  3743.  
  3744.     | restCmd |
  3745.     self scanAttribute.
  3746.     restCmd _ self token.
  3747.     ((restCmd = 'r') or: [restCmd = 'R'])
  3748.         ifFalse: [^self badAttribute].
  3749.     hadAttributeFlag _ restFlag _ true.!
  3750. xSpecial
  3751.     "Parses an Adagio special command. Special commands start with an exclaimation point (!!) and may not be combined on a line with other attributes."
  3752.  
  3753.     | cmd |
  3754.     self scanAttribute.
  3755.     cmd _ self token.
  3756.     (cmd = '!!tempo') ifTrue: [^self parseTempo].
  3757.     (cmd = '!!rate') ifTrue: [^self parseRate].
  3758.     (cmd = '!!endscore')
  3759.         ifTrue:
  3760.             [hadAttributeFlag _ false.
  3761.              tokenType _ #end.
  3762.              ^source setToEnd].
  3763.     "unknown special command"
  3764.     self error: 'bad special command', cmd.
  3765.     self specialCheck.!
  3766. xTime
  3767.     "Parses a time attribute. The time may be a positive number or it may be a symbolic duration. For example, 't60' = 'tq' at a tempo of 100; both cause the time to be set to one quarter note, or 60/100ths of a second, after the last synch point."
  3768.  
  3769.     | t |
  3770.     self scanAttribute.
  3771.     buffer next.
  3772.     (buffer atEnd) ifTrue: [^self badAttribute].
  3773.     (buffer peek isDigit)
  3774.         ifTrue:
  3775.             [t _ (self convertToNumber: buffer posOnly: true) * (100.0 / rate).
  3776.              t isNil ifTrue: [^self]]    "bad number; abort"
  3777.         ifFalse:
  3778.             [t _ (self parseDur) * (100.0 / tempo) * (100.0 / rate).
  3779.              t isNil ifTrue: [^self]].    "bad duration; abort"
  3780.     time _ synchPoint + t.
  3781.     notes startNewSublist.
  3782.     hadAttributeFlag _ true.!
  3783. xVoice
  3784.     "Parses a voice attribute (e.g. 'v3' sets the current voice to 3)."
  3785.  
  3786.     | v |
  3787.     self scanAttribute.
  3788.     buffer next.
  3789.     (buffer atEnd) ifTrue: [^self badAttribute].
  3790.     v _ self convertToNumber: buffer posOnly: true.
  3791.     (v isNil)
  3792.         ifTrue: [^self].    "bad number; abort"
  3793.     (v < 1) ifTrue:
  3794.             [self range: 'voice' value: v using: 1.
  3795.              v _ 1].
  3796.     (v > 16) ifTrue:
  3797.             [self range: 'voice' value: v using: 16.
  3798.              v _ 16].
  3799.     voice _ v.
  3800.     hadAttributeFlag _ true.! !
  3801.  
  3802. !AdagioParser methodsFor: 'scanning'!
  3803. nextChar
  3804.     "Read the next character of the source into hereChar. hereChar is set to EndChar when the source is exhausted."
  3805.  
  3806.     (hereChar _ source next) isNil
  3807.         ifTrue: [hereChar _ StopChar].!
  3808. nextToken
  3809.     "Read the next token from source, which is determined by looking at the first non-white space character. Set tokenType to indicate the type of the token just read."
  3810.  
  3811.     self skipWhiteSpace.
  3812.     tokenType _ typeTable at: hereChar asciiValue.
  3813.     "if x is the first letter of tokenType:"
  3814.     (tokenType at: 1) == $x
  3815.         ifTrue:
  3816.             ["then perform it to scan a note attribute token"
  3817.              self perform: tokenType]
  3818.         ifFalse:
  3819.             ["else this tokenType needs no further processing"
  3820.              self nextChar].!
  3821. peekAhead
  3822.     "Skip white space and peek at the type of the next character type."
  3823.  
  3824.     self skipWhiteSpace.
  3825.     ^typeTable at: hereChar asciiValue!
  3826. scanAttribute
  3827.     "Read a string of contiguous characters not containing spaces or delimiters."
  3828.  
  3829.     | cType |
  3830.     buffer resetAll.
  3831.     [cType _ typeTable at: hereChar asciiValue.
  3832.      (cType == #spacer) or:
  3833.       [(cType == #separator) or:
  3834.        [(cType == #semicolon) or:
  3835.         [(cType == #comma) or:
  3836.          [cType == #end]]]]]
  3837.             whileFalse:
  3838.                 [buffer nextPut: hereChar asLowercase.
  3839.                  self nextChar].
  3840.     buffer reset.
  3841.     tokenType _ #attribute.!
  3842. skipRestOfLine
  3843.     "Skip the remaining characters of this line."
  3844.  
  3845.     [((typeTable at: hereChar asciiValue) == #separator) or:
  3846.      [hereChar == StopChar]]
  3847.         whileFalse: [self nextChar].
  3848.     self nextChar.!
  3849. skipWhiteSpace
  3850.     "Skip white space."
  3851.  
  3852.     [(typeTable at: hereChar asciiValue) == #spacer]
  3853.         whileTrue: [self nextChar].! !
  3854.  
  3855. !AdagioParser methodsFor: 'private'!
  3856. badAttribute
  3857.  
  3858.     self badAttribute: self token.!
  3859. badAttribute: attributeString
  3860.  
  3861.     self report: 'Bad Adagio attribute: ', attributeString.!
  3862. convertToNumber: aStream posOnly: posOnlyFlag
  3863.     "Converts aStream to a number. Complain and answer nil if it contains non-digits."
  3864.     "Details: If aStream contains non-digits, 'Integer readFrom:' will not consume the entire stream."
  3865.  
  3866.     | val |
  3867.     val _ Integer readFrom: aStream radix: 10.
  3868.     aStream atEnd
  3869.         ifFalse:
  3870.             ["error parsing the contents of the stream; didn't read it all"
  3871.              self report: 'Only digits are expected here: ', self token.
  3872.              ^nil].    "return nil to indicate an error even if the user proceeds"
  3873.  
  3874.     (posOnlyFlag & (val < 0))
  3875.         ifTrue:
  3876.             ["only positive integers are allowed"
  3877.              self report: 'Only positive numbers are allowed here: ', self token.
  3878.              ^nil].    "return nil to indicate an error even if the user proceeds"
  3879.     ^val!
  3880. curDuration
  3881.     "A tempo of 100 means 100 quarter notes per minute, or 60 hundredths of a second per quarter note. A duration must be scaled by both the tempo and the rate. A rate of  '100' is normal, '200' is twice normal, etc. If the rate is doubled, the duration of each note must be cut in half."
  3882.  
  3883.     ^duration * (100.0 / tempo) * (100.0 / rate)!
  3884. curPitch
  3885.  
  3886.     ^(octave + 1) * 12 + pitchClass + modifier!
  3887. doNext
  3888.     "Scan the next token from the input and take appropriate action. Answer true when input is exhausted."
  3889.  
  3890.     self nextToken.    "sets tokenType"
  3891.     (tokenType == #attribute) ifTrue:
  3892.         [^false].
  3893.     (tokenType == #separator) ifTrue:
  3894.         ["Generate an event and advance time."
  3895.          self generateEvent: true.
  3896.          ^false].
  3897.     (tokenType == #semicolon) ifTrue:
  3898.         ["Generate an event and advance time."
  3899.          self generateEvent: true.
  3900.          ^false].
  3901.     (tokenType == #comma) ifTrue:
  3902.         ["Generate an event but do not advance time (comma separator)."
  3903.          self generateEvent: false.
  3904.          ^false].
  3905.     (tokenType == #xComment) ifTrue:
  3906.         [^false].
  3907.     (tokenType == #end) ifTrue:
  3908.         [self generateEvent: false.    "Generate the last event. Don't bother advancing time."
  3909.          ^true].
  3910.     "if we get here, we have encountered an unexpected character"
  3911.     self report: 'Unexpected character ', hereChar asciiValue printString.
  3912.     self skipRestOfLine.!
  3913. generateEvent: advanceFlag
  3914.  
  3915.     | note |
  3916.     hadAttributeFlag ifTrue:
  3917.         [restFlag ifFalse:
  3918.             [note _ NoteElement
  3919.                 new: (self curPitch)
  3920.                 at: (time truncated)
  3921.                 dur: (self curDuration truncated)
  3922.                 vel: loudness
  3923.                 voice: voice.
  3924.              notes add: note].
  3925.          (nextTimeDelta notNil)
  3926.             ifTrue:
  3927.                 ["always advance time if a nextTimeDelta attribute was given"
  3928.                 time _ time + nextTimeDelta.
  3929.                 nextTimeDelta _ nil]
  3930.             ifFalse:
  3931.                 ["advance time even if nextTimeDelta wasn't given, using the duration of the current note"
  3932.                  advanceFlag ifTrue: [time _ time + self curDuration]]].
  3933.  
  3934.     hadAttributeFlag _ restFlag _ false.!
  3935. range: attributeName value: offendingValue using: substitutedValue
  3936.     "Post a range error and correction notification."
  3937.  
  3938.     self report:
  3939.         offendingValue printString, ' is out of range for the ',
  3940.         attributeName, ' attribute; substituting ', substitutedValue printString.!
  3941. report: aString
  3942.     "Report an error."
  3943.  
  3944.     self error: aString.!
  3945. specialCheck
  3946.     "Special commands cannot be combined with other attributes. This method is to be called after parsing the arguments of a special command to be sure that no other attributes occur before the next separator."
  3947.  
  3948.     [(self peekAhead == #separator) or:
  3949.      [self peekAhead == #end]]
  3950.         whileFalse:
  3951.             [self skipWhiteSpace.
  3952.              self scanAttribute.
  3953.              self error: 'Attributes not allowed with special commands', self token].!
  3954. token
  3955.  
  3956.     ^buffer contents! !
  3957.  
  3958. PitchRider comment:
  3959. 'See my class comment.'!
  3960.  
  3961. MidiRecorder comment:
  3962. 'I am a recorder for Midi events. I can be used to record a score in real time. I can also overdub (record a new score while playing an existing one), monitor incoming Midi commands (either as raw bytes or as higher level commands), or support interactive performance (in which the computer performs in response to incoming Midi commands).
  3963.  
  3964. Midi controllers such as pitch benders and breath controllers generate large volumes of data which consume processor time. In cases where this information is not of interest to the program using it, it is best to filter it out as soon as possible. I support various options for doing this including filtering by Midi channel and/or by command type.'!
  3965.  
  3966. !MidiRecorder methodsFor: 'initialize-release'!
  3967. reset
  3968.     "Reset to a state of being ready to record Midi events."
  3969.  
  3970.     (times isNil)
  3971.         ifTrue:
  3972.             [limit _ InitialSize.
  3973.              times _ Array new: InitialSize.
  3974.              cmds _ Array new: InitialSize.
  3975.              arg1s _ Array new: InitialSize.
  3976.              arg2s _ Array new: InitialSize]
  3977.         ifFalse:
  3978.             [1 to: limit do:
  3979.                 [: index |
  3980.                      times at: index put: nil.
  3981.                      cmds at: index put: nil.
  3982.                      arg1s at: index put: nil.
  3983.                      arg2s at: index put: nil].
  3984.             ].
  3985.  
  3986.     next _ 1.
  3987.     state _ #idle.
  3988.     lastCmd _ nil.
  3989.     lastSelector _ nil.
  3990.     activeNotes _ nil.
  3991.     pedalNotes _ nil.
  3992.     inBuf _ ByteArray new: 4.!
  3993. resetMidiTable
  3994.     "Resets the Midi table to default table from my class."
  3995.  
  3996.     midiTable _ DefaultMidiTable deepCopy.! !
  3997.  
  3998. !MidiRecorder methodsFor: 'midi filtering'!
  3999. ignoreChan: chan
  4000.     "Don't record events on the given midi channel."
  4001.  
  4002.     ((chan isInteger not) | (chan < 1) | (chan > 16))
  4003.         ifTrue: [^self error: 'bad Midi channel specification'].
  4004.  
  4005.     "two-arg channel messages"
  4006.     #(128 144 160 176 224)
  4007.         do: [: msg |
  4008.             midiTable at: (msg bitOr: chan - 1) put: #ignoreTwo:].
  4009.  
  4010.     "one-arg channel messages"
  4011.     #(192 208)
  4012.         do: [: msg |
  4013.             midiTable at: (msg bitOr: chan - 1) put: #ignoreOne:].!
  4014. ignoreCmd: midiCmd
  4015.     "Ignore the given midi command on all channels."
  4016.  
  4017.     | cmd | 
  4018.  
  4019.     ((midiCmd isInteger not) | (midiCmd < 128) | (midiCmd > 255))
  4020.         ifTrue: [^self error: 'bad Midi command'].
  4021.  
  4022.     (#(240 241 244 245 247 249 253) includes: midiCmd)
  4023.         ifTrue:        "can't ignore any of these commands; they are not defined"
  4024.             [^self error: 'You can''t ignore this undefined Midi command: ', midiCmd printString].
  4025.  
  4026.     (midiCmd < 240)
  4027.         ifTrue:        "its a midi channel command"
  4028.             [cmd _ midiCmd bitAnd: 2r11110000.
  4029.              1 to: 16 do: [: chan |
  4030.                 midiTable
  4031.                     at: (cmd bitOr: chan - 1)
  4032.                     put: ((#(128 144 160 176 224) includes: cmd)
  4033.                                 ifTrue: [#ignoreTwo:]
  4034.                                 ifFalse: [#ignoreOne:])].
  4035.             ^self
  4036.         ].
  4037.  
  4038.     (#(246 248 250 251 252 254 255) includes: midiCmd)
  4039.         ifTrue:        "zero-arg commands"
  4040.             [midiTable at: midiCmd put: #ignore.
  4041.              ^self].
  4042.  
  4043.     (midiCmd = 243)
  4044.         ifTrue:        "one-arg command"
  4045.             [midiTable at: midiCmd put: #ignoreOne:.
  4046.              ^self].
  4047.  
  4048.     (midiCmd = 242)
  4049.         ifTrue:        "two-arg command"
  4050.             [midiTable at: midiCmd put: #ignoreTwo:.
  4051.              ^self].
  4052.  
  4053.     "we should not get here"
  4054.     self error: 'implementation error'.!
  4055. recordOnly: channelList
  4056.     "Turn off recording of all but the midi channels given.
  4057.      Midi channels are specified by numbers in the range 1-16."
  4058.  
  4059.     channelList do: [: chan |
  4060.         ((chan isInteger not) | (chan < 1) | (chan > 16))
  4061.             ifTrue: [^self error: 'bad Midi channel specification: ', chan printString]].
  4062.  
  4063.     1 to: 16 do: [: chan |
  4064.         (channelList includes: chan)
  4065.             ifFalse: [self ignoreChan: chan]].! !
  4066.  
  4067. !MidiRecorder methodsFor: 'midi monitor'!
  4068. monitor
  4069.     "Print midi messages to the transcript until any mouse button is pressed."
  4070.  
  4071.     self midiDo: [: cmd : arg1 : arg2 |
  4072.         self printCmd: cmd with: arg1 with: arg2].!
  4073. pollMidi: aBlock
  4074.     "Poll the incoming Midi stream in real time and call the given block for each Midi event. The block takes three arguments: the Midi command byte and two argument bytes. Depending on the command, the argument bytes may or may not be meaningful. It is up to the block to 'understand' Midi commands. See midiDo: for implementation details."
  4075.  
  4076.     | mSecsAtStart i |
  4077.     self recordData.
  4078.     (state == #idle) ifFalse: [^self].    "wait for a better moment..."
  4079.     i _ 1.
  4080.     [(i _ i + 1) < next] whileTrue:
  4081.         [aBlock
  4082.             value: (cmds at: i)
  4083.             value: (arg1s at: i)
  4084.             value: (arg2s at: i)].
  4085.     next _ 2.!
  4086. printCmd: cmd with: arg1 with: arg2
  4087.     "print the given midi command"
  4088.  
  4089.     | cmdType chan |
  4090.  
  4091.     cmdType _ cmd bitAnd: 2r11110000.
  4092.     chan _ (cmd bitAnd: 2r00001111) + 1.
  4093.  
  4094.     (cmdType == 128)
  4095.         ifTrue: [^Transcript show: ('key up: ', arg1 printString, ' vel: ', arg2 printString, ' chan: ', chan printString); cr].
  4096.     (cmdType == 144)
  4097.         ifTrue: [^Transcript show: ('key down: ', arg1 printString, ' vel: ', arg2 printString, ' chan: ', chan printString); cr].
  4098.     (cmdType == 160)
  4099.         ifTrue: [^Transcript show: ('key after touch: ', arg1 printString, ' vel: ', arg2 printString, ' chan: ', chan printString); cr].
  4100.     (cmdType == 176)
  4101.         ifTrue: [^Transcript show: ('controller: ', arg1 printString, ' val: ', arg2 printString, ' chan: ', chan printString); cr].
  4102.     (cmdType == 192)
  4103.         ifTrue: [^Transcript show: ('program change: ', arg1 printString, ' chan: ', chan printString); cr].
  4104.     (cmdType == 208)
  4105.         ifTrue: [^Transcript show: ('channel after touch ', arg1 printString, ' chan: ', chan printString); cr].
  4106.     (cmdType == 224)
  4107.         ifTrue: [^Transcript show: ('pitch bend: ', arg1 printString, ' ', arg2 printString, ' chan: ', chan printString); cr].
  4108.     (cmd == 240)
  4109.         ifTrue: [^Transcript show: ('system exclusive: ', (arg1 at: 1) printString, ' (', arg1 size printString, ' bytes)'); cr].
  4110.  
  4111.     Transcript show: 'cmd: ', cmd printString, ' arg1: ', arg1 printString, ' arg2: ', arg2 printString; cr.!
  4112. testmonitor: aStream
  4113.     "Print midi messages to the transcript until any mouse button is pressed. Use aStream as the source of Midi data. This method is used for debugging."
  4114.  
  4115.     | i |
  4116.     self reset.
  4117.     self startRecording.
  4118.     i _ 2.
  4119.     [aStream atEnd or: [Sensor anyButtonPressed]]
  4120.         whileFalse:
  4121.             [self processByte: (aStream next) asciiValue.
  4122.              (next > i)
  4123.                  ifTrue:
  4124.                     [self printCmd: (cmds at: i) with: (arg1s at: i) with: (arg2s at: i).
  4125.                      i _ i + 1].
  4126.              ((state == #idle) & (next == i) & (next > 2))
  4127.                 ifTrue: [next _ i _ 2]].
  4128.     self stopRecording.! !
  4129.  
  4130. !MidiRecorder methodsFor: 'record/overdub'!
  4131. echoTest
  4132.     "This test records your playing until a mouse button is pressed, then plays what you played back to you. Answers the recorded score."
  4133.     "MidiRecorder new echoTest"
  4134.  
  4135.     | score |
  4136.     self reset.
  4137.     score _ self record.
  4138.     [Sensor anyButtonPressed] whileTrue: ["wait for button to be released"].
  4139.     score playFrom: 0 rate: 1.
  4140.     ^score!
  4141. overDub: aScore
  4142.     "Record a new score while performing aScore from the beginning at normal speed. Stop when a mouse button is pressed. Answer the newly recorded 'track'."
  4143.  
  4144.     ^self overDub: aScore playFrom: 0 rate: 1!
  4145. overDub: aScore playFrom: startTime
  4146.     "Record a new score while performing aScore from the given starting point at normal speed. Stop when a mouse button is pressed. Answer the newly recorded 'track'."
  4147.  
  4148.     ^self overDub: aScore playFrom: startTime rate: 1!
  4149. overDub: aScore playFrom: startTime rate: rate
  4150.     "Record a new score while performing aScore from the given point at the given rate. Stop when a mouse button is pressed. Answer the newly recorded 'track'."
  4151.  
  4152.     | mSecsAtStart currTime |
  4153.     "ignore key after-pressure, program change, channel pressure (after-touch), and pitch wheel change commands:"
  4154.     #(160 192 208 224) do: [: cmd | self ignoreCmd: cmd].
  4155.     self reset.
  4156.  
  4157.     "Skip to the first note at or after the given time, processing all control changes and program changes along the way to establish the proper synthesizer state."
  4158.     aScore prepareToPlayFrom: startTime.
  4159.  
  4160.     "play aScore while recording"
  4161.     self startRecording.
  4162.     mSecsAtStart _ (Time millisecondClockValue) - (startTime * 10 // rate).
  4163.     [Sensor anyButtonPressed] whileFalse:
  4164.         [currTime _ ((Time millisecondClockValue - mSecsAtStart) * rate) // 10.
  4165.          aScore playThrough: currTime.
  4166.          self recordData].
  4167.     self stopRecording.
  4168.     aScore stopPlaying.
  4169.     self convertTimes: true rate: rate.
  4170.     ^self asScore!
  4171. record
  4172.     "Record a score from the Midi device until a mouse button is pressed."
  4173.  
  4174.     ^self overDub: Score new! !
  4175.  
  4176. !MidiRecorder methodsFor: 'interactive performance'!
  4177. arpeggio: delay intervals: intervals
  4178.     "Play an arpeggiated chord with the given intervals above the bottom note."
  4179.     "MidiRecorder new arpeggio: 20 intervals: #(4 7 10 7 4 0 4 7 10 7 4 0)"
  4180.  
  4181.     | chan nextTime |
  4182.     self midiDo:
  4183.         [: cmd : pitch : vel |
  4184.          (((cmd bitAnd: 2r11110000) == 144) & (vel > 0)) ifTrue:
  4185.             [chan _ (cmd bitAnd: 2r00001111) + 1.
  4186.              nextTime _ timeNow.
  4187.              intervals do:
  4188.                 [: i |
  4189.                  outQueue add:
  4190.                     (NoteElement
  4191.                         new: (pitch + i) at: nextTime
  4192.                         dur: delay vel: vel voice: chan).
  4193.                  outQueue add:
  4194.                     (NoteOff new: (pitch + i) at: (nextTime + delay - 1) voice: chan).
  4195.                  nextTime _ nextTime + delay]]].
  4196.     Midi allNotesOff.!
  4197. echoRate: delay count: count decay: decay
  4198.     "Echo the keyboard count times every delay msecs. Diminish the velocity by decay each time the note is repeated until it reaches zero."
  4199.     "MidiRecorder new echoRate: 18 count: 32 decay: 2"
  4200.  
  4201.     | chan echoVel echoTime |
  4202.     self midiDo:
  4203.         [: cmd : pitch : vel |
  4204.          ((cmd bitAnd: 2r11110000) == 144) ifTrue:
  4205.             [chan _ (cmd bitAnd: 2r00001111) + 1.
  4206.              echoVel _ vel.
  4207.              echoTime _ timeNow.
  4208.              count timesRepeat:
  4209.                 [(echoVel > 1) ifTrue:
  4210.                     [outQueue add:
  4211.                         (NoteElement
  4212.                             new: pitch at: echoTime
  4213.                             dur: delay vel: echoVel voice: chan).
  4214.                      outQueue add:
  4215.                         (NoteOff new: pitch at: (echoTime + delay - 1) voice: chan).
  4216.                      echoVel _ echoVel - decay.
  4217.                      echoTime _ echoTime + delay]]]].
  4218.     Midi allNotesOff.!
  4219. glissRate: delay count: count decay: decay
  4220.     "Echo the keyboard count times every delay msecs. Diminish the velocity by decay and increment the pitch each time the note is repeated."
  4221.     "MidiRecorder new glissRate: 4 count: 20 decay: 4"
  4222.  
  4223.     | chan echoVel echoTime echoPitch |
  4224.     self midiDo:
  4225.         [: cmd : pitch : vel |
  4226.          ((cmd bitAnd: 2r11110000) == 144 and: [(vel > 0) & (pitch >= 48)]) ifTrue:
  4227.             [chan _ (cmd bitAnd: 2r00001111) + 1.
  4228.              echoPitch _ pitch + 1.
  4229.              echoVel _ vel.
  4230.              echoTime _ timeNow.
  4231.              count timesRepeat:
  4232.                 [(echoVel > 1) ifTrue:
  4233.                     [outQueue add:
  4234.                         (NoteElement
  4235.                             new: echoPitch at: echoTime
  4236.                             dur: delay vel: echoVel voice: chan).
  4237.                      outQueue add:
  4238.                         (NoteOff
  4239.                             new: echoPitch at: (echoTime + delay - 1)
  4240.                             voice: chan).
  4241.                      echoPitch _ echoPitch + 1.
  4242.                      echoVel _ echoVel - decay.
  4243.                      echoTime _ echoTime + delay]]]].
  4244.     Midi allNotesOff.!
  4245. midiDo: aBlock
  4246.     "Interact with the incoming Midi stream in real time by calling the given block for each Midi event. The block takes three arguments: the Midi command byte and two argument bytes. Depending on the command, the argument bytes may or may not be meaningful. It is up to the block to 'understand' Midi commands. As usual, pressing any mouse button terminates the interaction."
  4247.     "Details: Set ourselves up to record as usual, but every time through the loop print the next command in the recording buffers. If the printing process catches up to the 'record head' (next), and we are in an idle state, reset the record head and i to the beginning."
  4248.  
  4249.     | mSecsAtStart i |
  4250.     self reset.
  4251.     outQueue _ MusicEventQueue new: 2000.
  4252.     mSecsAtStart _ Time millisecondClockValue.
  4253.     self startRecording.
  4254.     i _ 2.
  4255.     [Sensor anyButtonPressed]
  4256.         whileFalse:
  4257.             [timeNow _ (Time millisecondClockValue - mSecsAtStart) // 10.
  4258.              self playQueue.
  4259.              self recordData.
  4260.              (next > i)
  4261.                  ifTrue:
  4262.                     [timeNow _ (Time millisecondClockValue - mSecsAtStart) // 10.
  4263.                      aBlock
  4264.                         value: (cmds at: i)
  4265.                         value: (arg1s at: i)
  4266.                         value: (arg2s at: i).
  4267.                      i _ i + 1].
  4268.              ((state == #idle) & (next == i) & (next > 2))
  4269.                 ifTrue: [next _ i _ 2]].
  4270.     self stopRecording.!
  4271. playQueue
  4272.  
  4273.     [(outQueue size > 0) and:
  4274.      [(outQueue first time) <= timeNow]] whileTrue:
  4275.         [outQueue removeFirst perform].!
  4276. thirds
  4277.     "Play in thirds with the keyboard."
  4278.     "MidiRecorder new thirds"
  4279.  
  4280.     | cmdType chan |
  4281.     self midiDo:
  4282.         [: cmd : arg1 : arg2 |
  4283.          cmdType _ cmd bitAnd: 2r11110000.
  4284.          chan _ (cmd bitAnd: 2r00001111) + 1.
  4285.          (cmdType == 128)
  4286.             ifTrue: [Midi noteOff: arg1 + 4 chan: chan].
  4287.          (cmdType == 144)
  4288.             ifTrue: [Midi noteOn: arg1 + 4 vel: arg2 chan: chan]].! !
  4289.  
  4290. !MidiRecorder methodsFor: 'private - recording'!
  4291. recordData
  4292.  
  4293.     | stream |
  4294.     "try to read and process a block of characters from fileDescriptor"
  4295.     self recordData: Midi readStream.!
  4296. recordData: bufStream
  4297.     "Process the contents of bufStream as if it were input."
  4298.  
  4299.     [bufStream atEnd]
  4300.         whileFalse:
  4301.             [self processByte: bufStream next].!
  4302. startRecording
  4303.     "Start Midi recording."    
  4304.  
  4305.     | startTime |
  4306.     "reset  and flush midi port"
  4307.     Midi flushInput.
  4308.  
  4309.     "just assume there is enough space for the first entry"
  4310.     startTime _ LargePositiveInteger new: 4.
  4311.      Time millisecondClockInto: startTime.
  4312.     times at: 1 put: startTime.
  4313.     cmds at: 1 put: #start.
  4314.     next _ 2.!
  4315. stopRecording
  4316.     "Stop Midi recording."    
  4317.  
  4318.     | stopTime |
  4319.     stopTime _ LargePositiveInteger new: 4.
  4320.      Time millisecondClockInto: stopTime.
  4321.     (next > limit) ifTrue: [self growAll].
  4322.     times at: next put: stopTime.
  4323.     cmds at: next put: #stop.
  4324.     next _ next + 1.! !
  4325.  
  4326. !MidiRecorder methodsFor: 'private - table msgs'!
  4327. badTableEntry: aByte
  4328.     "Implementation error: there is a bad Midi table entry."
  4329.  
  4330.     self error: 'implementation error'.!
  4331. data: dataByte
  4332.     "Implementation error: you should not be using a data byte to index into the Midi action table."
  4333.  
  4334.     self error: 'implementation error'.!
  4335. endSysExclusive: cmdByte
  4336.     "We have received an unexpected 'end system exclusive' command."
  4337.  
  4338.     self error: 'unexpected ''End of System Exclusive'' command'.!
  4339. ignore: cmdByte
  4340.     "Ignore a zero-arg midi command."    
  4341.  
  4342.     "do nothing"!
  4343. ignoreOne: cmdByte
  4344.     "Ignore a one-arg midi command."    
  4345.  
  4346.     lastCmd _ cmdByte.
  4347.     lastSelector _ #ignoreOne:.
  4348.     state _ #ignore1.!
  4349. ignoreTwo: cmdByte
  4350.     "Ignore a two-arg midi command."    
  4351.  
  4352.     lastCmd _ cmdByte.
  4353.     lastSelector _ #ignoreTwo:.
  4354.     state _ #ignore2.!
  4355. recordOne: cmdByte
  4356.     "Record a one-arg midi command at the current time."    
  4357.  
  4358.     | currentTime |
  4359.     (next > limit) ifTrue: [self growAll].
  4360.     currentTime _ LargePositiveInteger new: 4.
  4361.      Time millisecondClockInto: currentTime.
  4362.     times at: next put: currentTime.
  4363.     cmds at: next put: cmdByte.
  4364.     lastCmd _ cmdByte.
  4365.     lastSelector _ #recordOne:.
  4366.     state _ #want1only.!
  4367. recordSysExclusive: cmdByte
  4368.     "The beginning of a variable length 'system exclusive' command."
  4369.  
  4370.     | currentTime |
  4371.     (next > limit) ifTrue: [self growAll].
  4372.     currentTime _ LargePositiveInteger new: 4.
  4373.      Time millisecondClockInto: currentTime.
  4374.     times at: next put: currentTime.
  4375.     cmds at: next put: cmdByte.
  4376.     arg1s at: next put: (OrderedCollection new: 1000).
  4377.         "Make a place to store the system exclusive message. The first byte of this collection will be the manufacture's ID number."
  4378.     arg2s at: next put: nil.
  4379.     lastCmd _ nil.
  4380.     lastSelector _ nil.
  4381.     state _ #sysExclusive.!
  4382. recordTwo: cmdByte
  4383.     "Record a two arg midi command at the current time."    
  4384.  
  4385.     | currentTime |
  4386.     (next > limit) ifTrue: [self growAll].
  4387.     currentTime _ LargePositiveInteger new: 4.
  4388.      Time millisecondClockInto: currentTime.
  4389.     times at: next put: currentTime.
  4390.     cmds at: next put: cmdByte.
  4391.     lastCmd _ cmdByte.
  4392.     lastSelector _ #recordTwo:.
  4393.     state _ #want1of2.!
  4394. undefined: cmdByte
  4395.     "We have received an undefined command."
  4396.  
  4397.     self error: 'undefined midi command ', cmdByte printString.! !
  4398.  
  4399. !MidiRecorder methodsFor: 'private - other'!
  4400. asScore
  4401.  
  4402.     | score cmd chan note |
  4403.     score _ Score new.
  4404.     activeNotes _ OrderedCollection new.
  4405.     1 to: (next - 1) do: [: i |
  4406.         ((cmds at: i) < 240)
  4407.             ifTrue:
  4408.                 [cmd _ (cmds at: i) bitAnd: 2r11110000.
  4409.                  chan _ (cmds at: i) bitAnd: 2r00001111]
  4410.             ifFalse:
  4411.                 [cmd _ cmds at: i.
  4412.                  chan _ nil].
  4413.         (cmd == 144)    "note on"
  4414.             ifTrue:
  4415.                 [((arg2s at: i) > 0)    "non-zero velocity"
  4416.                     ifTrue:
  4417.                         [note _ NoteElement
  4418.                             new: (arg1s at: i)
  4419.                             at: ((times at: i) asFloat / 10.0) rounded
  4420.                             dur: 60    "just a guess for now"
  4421.                             vel: (arg2s at: i)
  4422.                             voice: (chan + 1).
  4423.                         score add: note.
  4424.                         activeNotes add: note]
  4425.                     ifFalse:
  4426.                         [self setDur: (arg1s at: i) endTime: ((times at: i) asFloat / 10.0) rounded]]].
  4427.     ^score!
  4428. convertTimes: absFlag
  4429.     "Convert the absolute time in ticks to time since start of recording for all recorded events. If absFlag is true, then times are absolute. Otherwise, the starting time of the first recorded event is taken to be time zero."
  4430.  
  4431.     | timeAtStart |
  4432.     timeAtStart _ absFlag ifTrue: [times at: 1] ifFalse: [times at: 2].
  4433.     times at: 1 put: 0.
  4434.     2 to: times size do:
  4435.         [: index |
  4436.             times at: index put: ((times at: index) - timeAtStart).
  4437.             ((cmds at: index) == #stop) ifTrue: [^self]].!
  4438. convertTimes: absFlag rate: rate
  4439.     "Convert the absolute time in ticks to time since start of recording for all recorded events. If absFlag is true, then times are absolute. Otherwise, the starting time of the first recorded event is taken to be time zero."
  4440.  
  4441.     | timeAtStart |
  4442.     timeAtStart _ absFlag ifTrue: [times at: 1] ifFalse: [times at: 2].
  4443.     times at: 1 put: 0.
  4444.     2 to: times size do:
  4445.         [: index |
  4446.             times at: index put: (((times at: index) - timeAtStart) * rate) rounded.
  4447.             ((cmds at: index) == #stop) ifTrue: [^self]].!
  4448. growAll
  4449.     "Grow my recording space and set new limit."    
  4450.  
  4451.     times grow.
  4452.     cmds grow.
  4453.     arg1s grow.
  4454.     arg2s grow.
  4455.     limit _ times size.!
  4456. processByte: aByte
  4457.     "Process the given incoming Midi byte and record completed commands."
  4458.     "Details: Because this must be fast, it has been hand-tuned. Be careful!!"
  4459.  
  4460.     (aByte == 254) ifTrue: [^self].        "filter out active status messages"
  4461.     state == #idle
  4462.         ifTrue: [
  4463.             (aByte < 128)
  4464.                 ifFalse: [^self perform: (midiTable at: aByte) with: aByte]
  4465.                 ifTrue: [
  4466.                     (lastCmd notNil) ifTrue:
  4467.                         ["running status: process this data as if it had
  4468.                              a command byte like the lastCmd in front of it."
  4469.                          self perform: lastSelector with: lastCmd.
  4470.                          "the previous line has put us into a new state;
  4471.                          we now 'fall through' this case to process the
  4472.                         data byte given this new state. For this reason,
  4473.                         the (state==idle) case must be first."]]].
  4474.  
  4475.     state == #ignore1
  4476.         ifTrue: [^state _ #idle].
  4477.  
  4478.     state == #want2of2
  4479.         ifTrue: [
  4480.             arg2s at: next put: aByte.
  4481.             next _ next + 1.
  4482.             ^state _ #idle].
  4483.  
  4484.     state == #want1of2
  4485.         ifTrue: [
  4486.             arg1s at: next put: aByte.
  4487.             ^state _ #want2of2].
  4488.  
  4489.     state == #ignore2
  4490.         ifTrue: [^state _ #ignore1].
  4491.  
  4492.     state == #want1only
  4493.         ifTrue: [
  4494.             arg1s at: next put: aByte.
  4495.             next _ next + 1.
  4496.             ^state _ #idle].
  4497.  
  4498.     state == #sysExclusive
  4499.         ifTrue: [
  4500.             (aByte < 128)
  4501.                 ifTrue: [
  4502.                     "record a system exclusive data byte"
  4503.                     (arg1s at: next) addLast: aByte]
  4504.                 ifFalse: [
  4505.                     "a system exclusive message is terminated by any command byte"
  4506.                     next _ next + 1.
  4507.                     state _ #idle.
  4508.                     aByte == 247
  4509.                         ifTrue: [^self]                            "if endSysExclusive command, nothing left to do"
  4510.                         ifFalse: [^self processByte: aByte]]].    "otherwise, we must handle this new command"!
  4511. setDur: pitch endTime: endTime
  4512.     "Set the duration for the note(s) which just ended."
  4513.  
  4514.     | notes |
  4515.     notes _ activeNotes removeAllSuchThat: [: note | (note pitch == pitch)].
  4516.     notes do: [: note | note dur: (endTime - note time)].! !
  4517.  
  4518. Plan comment:
  4519. 'A Plan is a list of constraints to be executed in sequence to re-satisfy all currently satisfiable constraints in the face of one or more changing inputs.'!
  4520.  
  4521. !Plan methodsFor: 'initialize-release'!
  4522. initialize
  4523.  
  4524.     constraints _ OrderedCollection new: 2000.
  4525.     historyVariables _ OrderedCollection new: 2000.!
  4526. release
  4527.  
  4528.     constraints _ nil.
  4529.     historyVariables _ nil.! !
  4530.  
  4531. !Plan methodsFor: 'construction'!
  4532. append: aConstraint
  4533.     "Append the given constraint to this plan. Record its output variable if it is a HistoryVariable."
  4534.     "Details: The history variables of interest are those whose current state is changing. This can only happen if they are the output of some sort of constraint (including an input constraint). Furthermore, we only want to send the 'advanceHistory' message to the root of a history chain. This is guaranteed because only current states (roots) can be constraint outputs. Finally, edit and stay constraints are noops and are not recorded in the plan."
  4535.  
  4536.     (aConstraint includeInPlan) ifTrue:
  4537.         [constraints addLast: aConstraint].
  4538.     (aConstraint output class == HistoryVariable) ifTrue:
  4539.         [historyVariables add: aConstraint output].!
  4540. finalize
  4541.     "Turn the constraint and historyVariables collections into Arrays for faster execution."
  4542.  
  4543.     constraints _ constraints asArray.
  4544.     historyVariables _ historyVariables asArray.! !
  4545.  
  4546. !Plan methodsFor: 'interpretation'!
  4547. execute
  4548.     "Execute my constraints in order."
  4549.  
  4550.     Sensor leftShiftDown ifTrue: [Transcript show: '*** executing plan ***'; cr].
  4551.     historyVariables do: [:v | v advanceHistory].
  4552.     constraints do: 
  4553.         [:c | 
  4554.         c execute.
  4555.         Sensor leftShiftDown ifTrue: [Transcript show: c printString; cr]]!
  4556. size
  4557.  
  4558.     ^constraints size! !
  4559.  
  4560. !Plan methodsFor: 'compilation'!
  4561. compilePlan
  4562.     "Compile a method to execute this plan."
  4563.  
  4564.     | varDict codeStream |
  4565.     "collect variables and make a dictionary mapping variables to reference strings"
  4566.     varDict _ IdentityDictionary new.
  4567.     constraints do:
  4568.         [: c |
  4569.          c inputsDo: [: input | self record: input in: varDict].
  4570.          self record: c output in: varDict].
  4571.     variables _ Array new: (varDict size).
  4572.     varDict associations do:
  4573.         [: entry |
  4574.          variables at: (entry value) put: (entry key).
  4575.          varDict at: (entry key) put: ('(variables at: ', entry value printString, ')')].
  4576.     "collect the text for the constraints in order, mapping vars to '(variables at: index)'"
  4577.     codeStream _ (String new: 1000) writeStream.
  4578.     codeStream nextPutAll: 'CompiledPlan'; cr; cr.
  4579.     constraints do:
  4580.         [: c | c codeStringFor: varDict on: codeStream].
  4581.     "compile this as the method 'CompiledPlan' in class Plan"
  4582.     self class compile: codeStream contents classified: 'compilation'.!
  4583. record: aVariable in: aDictionary
  4584.     "Record the given variable in the given dictionary if it is not already there, and assign it a new index."
  4585.  
  4586.     (aDictionary includesKey: aVariable) ifFalse:
  4587.         [aDictionary at: aVariable put: (aDictionary size + 1)].! !
  4588.  
  4589. ClippingRectangle comment:
  4590. 'I support line clipping using the standard algorithm (see, e.g., Foley and vanDam''s book on interactive graphics). If I have zero area (because my height or width is zero) then I will report that no lines intersect me.'!
  4591.  
  4592. !ClippingRectangle methodsFor: 'clipping'!
  4593. clipFrom: beginPoint to: endPoint
  4594.     "Clip the line (beginPoint, endPoint) and answer an array of three elements, (drawFlag, clippedBegin, clippedEnd). If the first element of the answer is false, the line is completely outside the clipping rectangle, and need not be displayed. If the first element of answer is true, the second two elements are the beginning and ending points of the clipped line."
  4595.  
  4596.     | beginX beginY dx dy clippedBegin clippedEnd |
  4597.     self noArea ifTrue: ["line rejected" ^Array with: false with: nil with: nil].
  4598.     u0 _ 0.0.
  4599.     u1 _ 1.0.
  4600.     beginX _ beginPoint x.
  4601.     beginY _ beginPoint y.
  4602.     dx _ endPoint x - beginX.
  4603.     dy _ endPoint y - beginY.
  4604.  
  4605.     ((self clip: (beginX - xMin) delta: dx negated) and:
  4606.      [(self clip: (xMax - beginX) delta: dx) and:
  4607.      [(self clip: (beginY - yMin) delta: dy negated) and:
  4608.      [(self clip: (yMax - beginY) delta: dy)]]])
  4609.         ifFalse: ["line rejected" ^Array with: false with: nil with: nil].
  4610.  
  4611.     "If we haven't rejected the line by now, some of it must lie within the clipping rectangle. If u0 or u1 are within the open interval (0..1), use them to compute the new line segment start and/or point."
  4612.     dx _ dx asFloat.
  4613.     dy _ dy asFloat.
  4614.     (u0 > 0.0)
  4615.         ifTrue: [clippedBegin _ beginPoint +
  4616.                 ((dx asFloat * u0)@(dy asFloat * u0)) rounded]
  4617.         ifFalse: [clippedBegin _ beginPoint].
  4618.     (u1 < 1.0)
  4619.         ifTrue: [clippedEnd _ beginPoint +
  4620.                 ((dx asFloat * u1)@(dy asFloat * u1)) rounded]
  4621.         ifFalse: [clippedEnd _ endPoint].
  4622.     ^Array with: true with: clippedBegin with: clippedEnd!
  4623. noArea
  4624.     "Answer true if either my width or my height are zero."
  4625.  
  4626.     ^(xMin == xMax) | (yMin == yMax)! !
  4627.  
  4628. !ClippingRectangle methodsFor: 'private'!
  4629. clip: e delta: d
  4630.  
  4631.     | r |
  4632.     "Case 1: line parallel to boundary"
  4633.     (d = 0) ifTrue: [^e >= 0].        "accept if e is on boundary or inside"
  4634.  
  4635.     r _ e asFloat / d asFloat.        "the normalized intersection with the boundary"
  4636.     "Case 2: line from outside to inside"
  4637.     (d < 0) ifTrue:
  4638.         [(r > u1) ifTrue: [^false].        "reject"
  4639.          u0 _ u0 max: r.                "update u0 and accept"
  4640.          ^true].
  4641.     "Case 3: line from inside to outside"
  4642.     (d > 0) ifTrue:
  4643.         [(r < u0) ifTrue: [^false].        "reject"
  4644.          u1 _ u1 min: r.                "update u1 and accept"
  4645.          ^true].!
  4646. clipOrigin: origin corner: corner
  4647.     "This is the initialization message. corner should be >= origin, but if it isn't you will simply get an empty clipping rectangle."
  4648.  
  4649.     xMin _ origin x.
  4650.     yMin _ origin y.
  4651.     xMax _ xMin max: corner x.
  4652.     yMax _ yMin max: corner y.! !
  4653.  
  4654. Glyph comment:
  4655. 'I am an abstract class that defines the protocol used by components of a Scene to permit them to be laid out, displayed, and selected. Subclasses of me must implement the methods specified as ''subclassResponsibility'' (which are currently only locationPoints and boundingBox, but don''t trust this comment!!).'!
  4656.  
  4657. !Glyph methodsFor: 'initialize-release'!
  4658. initialize
  4659.     "Initialize myself with default values. Subclasses should do 'super initialize' when overriding this method to ensure that instance variables owned by their superclass are properly initialized."! !
  4660.  
  4661. !Glyph methodsFor: 'glyph protocol'!
  4662. boundingBox
  4663.     "Answer a Rectangle that completely surrounds all visible parts of me. By default, this is the smallest rectangle enclosing all my location points."
  4664.  
  4665.     | locations min max |
  4666.     locations _ self locationPoints.
  4667.     min _ max _ locations first.
  4668.     locations do:
  4669.         [: p |
  4670.          min _ min min: p.
  4671.          max _ max max: p].
  4672.     ^min corner: max!
  4673. changing
  4674.     "Answer true if my appearance depends on a constrained variable that is not a constant at plan execution time."
  4675.  
  4676.     self varsDo:
  4677.         [: v | (v stay not) ifTrue: [^true]].
  4678.     ^false!
  4679. containsPoint: aPoint
  4680.     "More complex glyphs may refine this method."
  4681.  
  4682.     ^self boundingBox containsPoint: aPoint!
  4683. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  4684.     "Draw myself. The default is to do nothing. Visible glyphs supply a more specialized behavior for this method."!
  4685. glyphsComment
  4686.     "This protocol describes the basic operations on graphical objects known as 'glyphs'. A glyph may be displayed, selected, and moved. Glyphs may be hierarchically composed of other glyphs. For example, a LineGlyph might be built from two PointGlyphs. A higher-level glyph often makes the glyphs of its component parts available for display, selection, and input operations. However, sometimes a glyph hides some of its component glyphs or some aspect of the behavior of those glyphs, such as the ability to select them. Thus, there are different messages for enumerating the subglyphs of a glyph for various purposes.  The default behavior of these operations is to simply enumerate all the subglyphs but any glyph my override this behavior to control the visibility of its subparts. The three categories of glyphs are:
  4687.  
  4688.     1. visible glyphs -- glyphs that are visible in the display
  4689.     2. selectable glyphs -- glyphs that can be selected and moved
  4690.     3. input glyphs -- glyphs that respond to keyboard and/or mouse events
  4691.  
  4692. These categories are orthogonal, so it is possible to have visible glyphs that cannot be selected and moved or glyphs that can be selected but are not visible (such as the end points of a PlainLine).
  4693.  
  4694. All glyphs must respond to basic glyph protocol:
  4695.     locationPoints -- Essential!!
  4696.     displayOn:at:clip:
  4697.     boundingBox
  4698.     initialize
  4699. The only essential message is locationPoints; default behavior is provided for the other messages, although since the default displayOn:at:clip: behavior is to do nothing, a glyph that does not override this default will not be visible!! 
  4700.  
  4701. If a glyph is an input glyph, it must also respond to one of:
  4702.     wantsKeystrokes
  4703.     wantsMouse
  4704. and, if it answers 'true' to one of these messages, it must support the corresponding keyboard and/or mouse prototcol."!
  4705. highlightOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  4706.     "This is the default highlighting method. It simply then draws a box around the glyph. Subclasses may choose different behavior."
  4707.  
  4708.     aDisplayMedium
  4709.         border: ((self boundingBox translateBy: aDisplayPoint)
  4710.                     insetOriginBy: -1@-1 cornerBy: -1@-1)
  4711.         widthRectangle: (1@1 corner: 1@1)
  4712.         mask: (Form black)
  4713.         clippingBox: clipBox.!
  4714. intersects: aRectOrGlyph
  4715.     "Answer true if I intersect the given object, which may be either a Rectangle or another Glyph."
  4716.  
  4717.     (aRectOrGlyph isMemberOf: Rectangle)
  4718.         ifTrue:
  4719.             [^aRectOrGlyph intersects: self boundingBox]
  4720.         ifFalse:
  4721.             [^aRectOrGlyph boundingBox intersects: self boundingBox].!
  4722. isGlyph
  4723.     "Yes, I am a glyph."
  4724.  
  4725.     ^true!
  4726. isSelectable
  4727.     "By default, glyphs are not selectable."
  4728.  
  4729.     ^false!
  4730. isVisible
  4731.     "By default, glyphs are visible."
  4732.  
  4733.     ^true!
  4734. locationPoints
  4735.     "Answer a collection of PointGlyphs that determine my location. These points are used to move the glyph."
  4736.  
  4737.     self subclassResponsibility! !
  4738.  
  4739. !Glyph methodsFor: 'moving'!
  4740. center
  4741.  
  4742.     | locations |
  4743.     locations _ self locationPoints.
  4744.     (locations size = 1)
  4745.         ifTrue: [^locations at: 1]
  4746.         ifFalse:
  4747.             [^(locations
  4748.                 inject: 0@0
  4749.                 into: [: total : p | total + p]) // locations size].!
  4750. moveTo: aPoint
  4751.  
  4752.     | locations center newLocations |
  4753.     locations _ self locationPoints.
  4754.     (locations size = 1) ifTrue:    "easy case: one point"
  4755.         [(locations at: 1) x: aPoint x; y: aPoint y.
  4756.          ^self].
  4757.  
  4758.     center _ self center.
  4759.     newLocations _ self locationPoints collect:
  4760.         [: p | aPoint + (p - center)].
  4761.     self locationPoints with: newLocations do:
  4762.         [: p : newLocation |
  4763.          p x: newLocation x.
  4764.          p y: newLocation y].! !
  4765.  
  4766. !Glyph methodsFor: 'merging'!
  4767. canMergeWith: aGlyph
  4768.     "Answer true if I can be merged with the given glyph. This is false by default. If this method answers 'true' then a method for 'mergeWith:' must also be provided."
  4769.  
  4770.     ^false!
  4771. extractFromMerge
  4772.     "Remove all merge constraints from this glyph."
  4773.  
  4774.     self varsDo:
  4775.         [: var |
  4776.          var constraints copy do:
  4777.              [: c |
  4778.               (c isMergeConstraint) ifTrue:
  4779.                 [c destroyConstraint]]].!
  4780. mergeWith: aGlyph
  4781.     "Add equality constraints between significant parts of me and the given glyph. The subclass must override this method if 'canMergeWith:' may return true."
  4782.  
  4783.     self subclassResponsibility! !
  4784.  
  4785. !Glyph methodsFor: 'enumeration'!
  4786. includesObjectIn: objectList
  4787.     "Answer true if I include one of the given given objects as a subpart or if I am one of the given objects."
  4788.  
  4789.     | i subPart |
  4790.     (objectList includes: self) ifTrue: [^true].
  4791.  
  4792.     "1 to: self class instSize do: [: i |"
  4793.     i _ self class instSize.
  4794.     [i > 0] whileTrue:
  4795.         [subPart _ self instVarAt: i.
  4796.          (objectList includes: subPart) ifTrue: [^true].
  4797.          ((subPart isGlyph) and:
  4798.            [subPart includesObjectIn: objectList]) ifTrue:
  4799.             [^true].
  4800.          i _ i - 1].
  4801.     ^false!
  4802. inputGlyphsDo: aBlock
  4803.     "Recursively enumerate the subparts of me that might want input."
  4804.  
  4805.     | i subPart |
  4806.     (self wantsKeystrokes | self wantsMouse) ifTrue:
  4807.         [aBlock value: self].
  4808.  
  4809.     "1 to: self class instSize do: [: i |"
  4810.     i _ self class instSize.
  4811.     [i > 0] whileTrue:
  4812.         [subPart _ self instVarAt: i.
  4813.          (subPart isGlyph) ifTrue:
  4814.             [subPart inputGlyphsDo: aBlock].
  4815.          i _ i - 1].!
  4816. selectableGlyphsDo: aBlock
  4817.     "Recursively enumerate the selectable subparts of me."
  4818.  
  4819.     | i subPart |
  4820.     (self isSelectable) ifTrue: [aBlock value: self].
  4821.  
  4822.     "1 to: self class instSize do: [: i |"
  4823.     i _ self class instSize.
  4824.     [i > 0] whileTrue:
  4825.          [subPart _ self instVarAt: i.
  4826.           (subPart isGlyph) ifTrue:
  4827.             [subPart selectableGlyphsDo: aBlock].
  4828.          i _ i - 1].!
  4829. varsDo: aBlock
  4830.     "Invoke the given block on all constrained variables owned by me."
  4831.  
  4832.     | i subPart |
  4833.     "1 to: self class instSize do: [: i |"
  4834.     i _ self class instSize.
  4835.     [i > 0] whileTrue:
  4836.         [subPart _ self instVarAt: i.
  4837.          ((subPart class == ConstrainedVariable) or: [subPart class == HistoryVariable]) ifTrue:
  4838.             [aBlock value: subPart].
  4839.          (subPart isGlyph) ifTrue:
  4840.             [subPart varsDo: aBlock].
  4841.          i _ i - 1].!
  4842. visibleGlyphsDo: aBlock
  4843.     "Recursively enumerate the visible subparts of me."
  4844.  
  4845.     | i subPart |
  4846.     (self isVisible) ifTrue: [aBlock value: self].
  4847.  
  4848.     "1 to: self class instSize do: [: i |"
  4849.     i _ self class instSize.
  4850.     [i > 0] whileTrue:
  4851.          [subPart _ self instVarAt: i.
  4852.           (subPart isGlyph) ifTrue:
  4853.             [subPart visibleGlyphsDo: aBlock].
  4854.          i _ i - 1].! !
  4855.  
  4856. !Glyph methodsFor: 'keyboard'!
  4857. handleKeystroke: aCharacter view: aView
  4858.     "Accept the given character. The default behavior is to do nothing."!
  4859. keystrokeVars
  4860.     "Answer a collection of DBVariables to which to attach edit constraints for handling keyboard input."
  4861.  
  4862.     ^#()!
  4863. wantsKeystrokes
  4864.     "Answer true if I want to get keyboard input. The default behavior is to answer false."
  4865.  
  4866.     ^false! !
  4867.  
  4868. !Glyph methodsFor: 'mouse'!
  4869. handleMouseDown: mousePoint view: aView
  4870.     "The mouse button has been pressed. mousePoint is in local coordinates. The default behavior is to do nothing."!
  4871. handleMouseMove: mousePoint view: aView
  4872.     "The message is sent repeatedly while the mouse button is pressed. mousePoint is in local coordinates. The default behavior is to do nothing."!
  4873. handleMouseUp: mousePoint view: aView
  4874.     "The mouse button has gone up. mousePoint is in local coordinates. The default behavior is to do nothing."!
  4875. mouseComment
  4876.  
  4877.     "When mouse input is initiated, the following sequence of events occurs:
  4878.     1. handleMouseDown:view: is sent to the glyph
  4879.     2. handleMouseMove: is sent to the glyph repeatedly while the mouse is down
  4880.     3. handleMouseUp: is sent to the glyph
  4881.  
  4882. All of these messages have two arguments: 1) the current mouse position in local coordinates and 2) the view in which this Glyph appears."!
  4883. wantsMouse
  4884.     "Answer true if I want to be informed of mouse activity. The default behavior is to answer false."
  4885.  
  4886.     ^false! !
  4887.  
  4888. !Glyph methodsFor: 'utilities'!
  4889. compile: aString
  4890.     "Answer the evaluation of the given code string (which is usually a block). The code is evaluated in the context of this glyph, so it may access the glyph's instance variables."
  4891.  
  4892.     ^Compiler
  4893.         evaluate: aString
  4894.         for: self
  4895.         logged: false!
  4896. fill: aRectangle mask: maskForm on: aDisplayMedium at: aDisplayPoint clip: clipBox
  4897.  
  4898.     (BitBlt
  4899.         destForm: aDisplayMedium
  4900.         sourceForm: nil
  4901.         halftoneForm: maskForm
  4902.         combinationRule: (Form over)
  4903.         destOrigin: (aRectangle origin + aDisplayPoint)
  4904.         sourceOrigin: (0@0)
  4905.         extent: (aRectangle extent)
  4906.         clipRect: clipBox)
  4907.             copyBits.!
  4908. hLineFrom: p1 length: length on: aDisplayMedium at: aDisplayPoint clip: clipBox
  4909.  
  4910.     (BitBlt 
  4911.         destForm: aDisplayMedium
  4912.         sourceForm: nil
  4913.         halftoneForm: (Form black)
  4914.         combinationRule: (Form over)
  4915.         destOrigin: ((p1 + aDisplayPoint) rounded)
  4916.         sourceOrigin: (0@0)
  4917.         extent: (length rounded@1)
  4918.         clipRect: clipBox) copyBits.!
  4919. lineFrom: p1 to: p2 on: aDisplayMedium at: aDisplayPoint clip: clipBox
  4920.     "Draw a one-bit thick line between the given points."
  4921.  
  4922.     aDisplayMedium
  4923.         drawLine: ((Form extent: 1@1) black)
  4924.         from: ((aDisplayPoint + p1) rounded)
  4925.         to: ((aDisplayPoint + p2) rounded)
  4926.         clippingBox: clipBox
  4927.         rule: (Form over)
  4928.         mask: (Form black).!
  4929. vLineFrom: p1 length: length on: aDisplayMedium at: aDisplayPoint clip: clipBox
  4930.  
  4931.     (BitBlt 
  4932.         destForm: aDisplayMedium
  4933.         sourceForm: nil
  4934.         halftoneForm: (Form black)
  4935.         combinationRule: (Form over)
  4936.         destOrigin: ((p1 + aDisplayPoint) rounded)
  4937.         sourceOrigin: (0@0)
  4938.         extent: (1@length rounded)
  4939.         clipRect: clipBox) copyBits.! !
  4940.  
  4941. !StaffLineGlyph methodsFor: 'initialize-release'!
  4942. initialize
  4943.  
  4944.     super initialize.
  4945.     origin _ PointGlyph new moveTo: 10@10.
  4946.     length _ FreeVariable value: 60.! !
  4947.  
  4948. !StaffLineGlyph methodsFor: 'accessing'!
  4949. length
  4950.  
  4951.     ^length value!
  4952. length: aNumber
  4953.  
  4954.     length setValue: aNumber.!
  4955. lengthVar
  4956.  
  4957.     ^length!
  4958. origin
  4959.  
  4960.     ^origin! !
  4961.  
  4962. !StaffLineGlyph methodsFor: 'glyph protocol'!
  4963. boundingBox
  4964.  
  4965.     ^(origin - (1@1)) extent: ((length value + 2)@3)!
  4966. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  4967.  
  4968.     (BitBlt 
  4969.         destForm: aDisplayMedium
  4970.         sourceForm: nil
  4971.         halftoneForm: (Form gray)
  4972.         combinationRule: (Form under)
  4973.         destOrigin: ((origin + aDisplayPoint) rounded)
  4974.         sourceOrigin: (0@0)
  4975.         extent: (length value@1)
  4976.         clipRect: clipBox) copyBits.!
  4977. locationPoints
  4978.  
  4979.     ^Array with: origin!
  4980. selectableGlyphsDo: aBlock
  4981.     "I have none."!
  4982. visibleGlyphsDo: aBlock
  4983.     "I'm the only visible part."
  4984.  
  4985.     aBlock value: self.! !
  4986.  
  4987. !LineGlyph methodsFor: 'initialize-release'!
  4988. initialize
  4989.  
  4990.     super initialize.
  4991.     p1 _ PointGlyph new moveTo: 10@10.
  4992.     p2 _ PointGlyph new moveTo: 40@40.! !
  4993.  
  4994. !LineGlyph methodsFor: 'accessing'!
  4995. p1
  4996.  
  4997.     ^p1!
  4998. p2
  4999.  
  5000.     ^p2! !
  5001.  
  5002. !LineGlyph methodsFor: 'glyph protocol'!
  5003. boundingBox
  5004.  
  5005.     ^p1 boundingBox merge: p2 boundingBox!
  5006. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  5007.     "Display the line connecting my endpoints."
  5008.  
  5009.     self
  5010.         lineFrom: p1
  5011.         to: p2
  5012.         on: aDisplayMedium
  5013.         at: aDisplayPoint
  5014.         clip: clipBox.!
  5015. locationPoints
  5016.  
  5017.     ^Array with: p1 with: p2! !
  5018.  
  5019. !PlainLineGlyph methodsFor: 'glyph protocol'!
  5020. selectableGlyphsDo: aBlock
  5021.  
  5022.     aBlock value: p1; value: p2.!
  5023. visibleGlyphsDo: aBlock
  5024.  
  5025.     aBlock value: self.! !
  5026.  
  5027. !WireGlyph methodsFor: 'initialize-release'!
  5028. initialize
  5029.  
  5030.     super initialize.
  5031.     p1 _ InvisibleWiringNodeGlyph new moveTo: 10@10.
  5032.     p2 _ InvisibleWiringNodeGlyph new moveTo: 40@40.! !
  5033.  
  5034. !VectorGlyph methodsFor: 'initialize-release'!
  5035. addConstraints
  5036.  
  5037.     (ArrowC isNil) ifTrue:
  5038.         [ArrowC _ Constraint
  5039.             names: #(vector p1 p2)
  5040.             methods: #('vector _ p2 - p1')].
  5041.     (DirectionC isNil) ifTrue:
  5042.         [DirectionC _ Constraint
  5043.             names: #(p1 p2 oldP1 oldP2)
  5044.             methods: #('p2 _ p1 + (oldP2 - oldP1)')].
  5045.  
  5046.     "constraints to attach and align arrow head"
  5047.     (p2 xVar) requireEquals: (arrowHead location xVar).
  5048.     (p2 yVar) requireEquals: (arrowHead location yVar).
  5049.     (ArrowC copy) var: (arrowHead vector xVar) var: (p1 xVar) var: (p2 xVar) strength: #required.
  5050.     (ArrowC copy) var: (arrowHead vector yVar) var: (p1 yVar) var: (p2 yVar) strength: #required.
  5051.  
  5052.     "constraints to maintain vector length and direction when moving p1"
  5053.     (DirectionC copy)
  5054.         var: (p1 xVar) var: (p2 xVar)
  5055.         var: (p1 xVar last) var: (p2 xVar last) strength: #default.
  5056.     (DirectionC copy)
  5057.         var: (p1 yVar) var: (p2 yVar)
  5058.         var: (p1 yVar last) var: (p2 yVar last) strength: #default.!
  5059. initialize
  5060.     "p1 is the base of the vector, a RodNode.
  5061.      p2 is the head of the vector, an InvisiblePointGlyph.
  5062.      This means that p2 can be moved but not merged with other RodNodes."
  5063.  
  5064.     super initialize.
  5065.     p1 _ SpringNodeGlyph new moveTo: 10@10.
  5066.     p2 _ InvisiblePointGlyph new moveTo: 30@30.
  5067.     arrowHead _ ArrowHeadGlyph new.
  5068.     self addConstraints.! !
  5069.  
  5070. !VectorGlyph methodsFor: 'accessing'!
  5071. arrowHead
  5072.  
  5073.     ^arrowHead! !
  5074.  
  5075. !PlanetVectorGlyph methodsFor: 'initialize-release'!
  5076. addConstraints
  5077.     | ArrowC |
  5078.     ArrowC isNil ifTrue: [ArrowC _ Constraint names: #(vector p1 p2 ) methods: #('vector _ p2 - p1' 'p2 _ p1 + vector' )].
  5079.     p2 xVar requireEquals: arrowHead location xVar.
  5080.     p2 yVar requireEquals: arrowHead location yVar.
  5081.     ArrowC copy
  5082.         var: arrowHead vector xVar
  5083.         var: p1 xVar
  5084.         var: p2 xVar
  5085.         strength: #required.
  5086.     ArrowC copy
  5087.         var: arrowHead vector yVar
  5088.         var: p1 yVar
  5089.         var: p2 yVar
  5090.         strength: #required!
  5091. initialize
  5092.     "p1 is the base of the vector, a PointGlyph.
  5093.      p2 is the head of the vector, an InvisiblePointGlyph"
  5094.  
  5095.     super initialize.
  5096.     p1 _ PointGlyph new moveTo: 10@10.
  5097.     p2 _ InvisiblePointGlyph new moveTo: 30@30.
  5098.     arrowHead _ ArrowHeadGlyph new.
  5099.     self addConstraints.! !
  5100.  
  5101. !PlanetVectorGlyph methodsFor: 'accessing'!
  5102. arrowHead
  5103.     ^arrowHead! !
  5104.  
  5105. !NoteGlyph methodsFor: 'initialize-release'!
  5106. initialize
  5107.  
  5108.     super initialize.
  5109.     center _ InvisiblePointGlyph new.
  5110.     start _ FreeVariable value: 0.
  5111.     duration _ FreeVariable value: 60.
  5112.     pitch _ FreeVariable new value: 60.
  5113.     modifier _ FreeVariable new value: #normal.
  5114.         "modifier is one of: #(normal, sharp, dSharp, flat, dFlat, natural)"
  5115.     velocity _ FreeVariable value: 64.
  5116.     voice _ FreeVariable value: 1.
  5117.     selected _ FreeVariable value: false.!
  5118. release
  5119.  
  5120.     center xVar release.
  5121.     center yVar release.
  5122.     start release.
  5123.     duration release.
  5124.     pitch release.
  5125.     modifier release.
  5126.     velocity release.
  5127.     voice release.
  5128.     selected release.
  5129.     self initialize.! !
  5130.  
  5131. !NoteGlyph methodsFor: 'accessing'!
  5132. duration
  5133.  
  5134.     ^duration value!
  5135. duration: aNumber
  5136.  
  5137.     duration setValue: aNumber.!
  5138. durationVar
  5139.  
  5140.     ^duration!
  5141. midiPitch
  5142.  
  5143.     | modTable myPitch |
  5144.     modTable _ Dictionary new.
  5145.     modTable at: #normal put: 0.
  5146.     modTable at: #dFlat put: -2.
  5147.     modTable at: #flat put: -1.
  5148.     modTable at: #natural put: 0.
  5149.     modTable at: #sharp put: 1.
  5150.     modTable at: #dSharp put: 2.
  5151.     myPitch _ pitch value.
  5152.     ^((myPitch // 7) * 12) +
  5153.         (#(0 2 4 5 7 9 11) at: ((myPitch \\ 7) + 1)) +
  5154.         (modTable at: modifier value)!
  5155. modifier
  5156.  
  5157.     ^modifier value!
  5158. modifier: aSymbol
  5159.  
  5160.     modifier setValue: aSymbol.!
  5161. modifierVar
  5162.  
  5163.     ^modifier!
  5164. pitch
  5165.  
  5166.     ^pitch value!
  5167. pitch: aNumber
  5168.  
  5169.     pitch setValue: aNumber.!
  5170. pitchVar
  5171.  
  5172.     ^pitch!
  5173. selected
  5174.  
  5175.     ^selected value!
  5176. selected: aBoolean
  5177.  
  5178.     selected setValue: aBoolean.!
  5179. selectedVar
  5180.  
  5181.     ^selected!
  5182. setIndex: aNumber
  5183.  
  5184.     center xVar
  5185.         setValue: (aNumber * 18) + 32
  5186.         strength: #required.!
  5187. start
  5188.  
  5189.     ^start value!
  5190. start: aNumber
  5191.  
  5192.     start setValue: aNumber.!
  5193. startVar
  5194.  
  5195.     ^start!
  5196. velocity
  5197.  
  5198.     ^velocity value!
  5199. velocity: aNumber
  5200.  
  5201.     velocity setValue: aNumber.!
  5202. velocityVar
  5203.  
  5204.     ^velocity!
  5205. voice
  5206.  
  5207.     ^voice value!
  5208. voice: aNumber
  5209.  
  5210.     voice setValue: aNumber.!
  5211. voiceVar
  5212.  
  5213.     ^voice! !
  5214.  
  5215. !NoteGlyph methodsFor: 'comparing'!
  5216. <= aNoteGlyph
  5217.  
  5218.     ^start value <= aNoteGlyph start! !
  5219.  
  5220. !NoteGlyph methodsFor: 'glyph protocol'!
  5221. boundingBox
  5222.  
  5223.     ^(center - (9@12)) extent: 18@24!
  5224. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  5225.  
  5226.     | forms |
  5227.     forms _ (selected value)
  5228.         ifTrue: [SelectedForms]
  5229.         ifFalse: [Forms].
  5230.     (forms at: modifier value)
  5231.         displayOn: aDisplayMedium
  5232.         at: (aDisplayPoint + center)
  5233.         clippingBox: clipBox
  5234.         rule: (Form paint)
  5235.         mask: (Form black).!
  5236. isSelectable
  5237.  
  5238.     ^true!
  5239. locationPoints
  5240.  
  5241.     ^Array with: center! !
  5242.  
  5243. !NoteGlyph methodsFor: 'keyboard'!
  5244. handleKeystroke: aCharacter view: aView
  5245.     "Handle a keystroke:
  5246.         m -> toggle selected
  5247.         space -> no modifier
  5248.         s -> sharper
  5249.         f -> flatter
  5250.         n -> natural"
  5251.  
  5252.     (aCharacter = Character space) ifTrue:
  5253.         [modifier value: #normal].
  5254.     (aCharacter = $f) ifTrue:
  5255.         [((modifier value) = #flat)
  5256.             ifTrue: [modifier value: #dFlat]
  5257.             ifFalse: [modifier value: #flat]].
  5258.     (aCharacter = $m) ifTrue:
  5259.         [selected value: (selected value not)].
  5260.     (aCharacter = $n) ifTrue:
  5261.         [modifier value: #natural].
  5262.     (aCharacter = $s) ifTrue:
  5263.         [((modifier value) = #sharp)
  5264.             ifTrue: [modifier value: #dSharp]
  5265.             ifFalse: [modifier value: #sharp]].!
  5266. keystrokeVars
  5267.  
  5268.     ^Array with: modifier with: selected!
  5269. wantsKeystrokes
  5270.  
  5271.     ^true! !
  5272.  
  5273. !NoteGlyph methodsFor: 'printing'!
  5274. printOn: aStream
  5275.  
  5276.     aStream nextPutAll: 't: ',  start value printString, ' p: ', pitch value printString; cr.! !
  5277.  
  5278. !GrandStaffGlyph methodsFor: 'all'!
  5279. addConstraints
  5280.  
  5281.     | spaceSize |
  5282.     (WidthC == nil) ifTrue:
  5283.         [WidthC _ Constraint
  5284.             names: #(left width right)
  5285.             methods: #('right _ left + width'   'left _ right - width'   'width _ right - left')].
  5286.  
  5287.     l1 lengthVar defaultStay.
  5288.     OffsetConstraint fromPoint: l1 origin to: leftBar p1 require: 0@0.
  5289.     OffsetConstraint fromPoint: l10 origin to: leftBar p2 require: 0@0.
  5290.     (WidthC copy) var: l1 origin xVar var: l1 lengthVar var: rightBar p1 xVar strength: #required.
  5291.     rightBar p1 xVar requireEquals: rightBar p2 xVar.
  5292.     rightBar p1 yVar requireEquals: l1 origin yVar.
  5293.     rightBar p2 yVar requireEquals: l10 origin yVar.
  5294.  
  5295.     spaceSize _ 4.
  5296.     OffsetConstraint fromPoint: l1 origin to: l2 origin require: 0@spaceSize.
  5297.     OffsetConstraint fromPoint: l2 origin to: l3 origin require: 0@spaceSize.
  5298.     OffsetConstraint fromPoint: l3 origin to: l4 origin require: 0@spaceSize.
  5299.     OffsetConstraint fromPoint: l4 origin to: l5 origin require: 0@spaceSize.
  5300.     OffsetConstraint fromPoint: l5 origin to: l6 origin require: 0@(2 * spaceSize).
  5301.     OffsetConstraint fromPoint: l6 origin to: l7 origin require: 0@spaceSize.
  5302.     OffsetConstraint fromPoint: l7 origin to: l8 origin require: 0@spaceSize.
  5303.     OffsetConstraint fromPoint: l8 origin to: l9 origin require: 0@spaceSize.
  5304.     OffsetConstraint fromPoint: l9 origin to: l10 origin require: 0@spaceSize.
  5305.     l2 lengthVar requireEquals: l1 lengthVar.
  5306.     l3 lengthVar requireEquals: l1 lengthVar.
  5307.     l4 lengthVar requireEquals: l1 lengthVar.
  5308.     l5 lengthVar requireEquals: l1 lengthVar.
  5309.     l6 lengthVar requireEquals: l1 lengthVar.
  5310.     l7 lengthVar requireEquals: l1 lengthVar.
  5311.     l8 lengthVar requireEquals: l1 lengthVar.
  5312.     l9 lengthVar requireEquals: l1 lengthVar.
  5313.     l10 lengthVar requireEquals: l1 lengthVar.!
  5314. initialize
  5315.  
  5316.     score _ #().
  5317.     staffIndex _ 0.
  5318.     timeScale _ FreeVariable value: 1.
  5319.     leftBar _ PlainLineGlyph new.
  5320.     rightBar _ PlainLineGlyph new.
  5321.     l1 _ StaffLineGlyph new.
  5322.     l2 _ StaffLineGlyph new.
  5323.     l3 _ StaffLineGlyph new.
  5324.     l4 _ StaffLineGlyph new.
  5325.     l5 _ StaffLineGlyph new.
  5326.     l6 _ StaffLineGlyph new.
  5327.     l7 _ StaffLineGlyph new.
  5328.     l8 _ StaffLineGlyph new.
  5329.     l9 _ StaffLineGlyph new.
  5330.     l10 _ StaffLineGlyph new.
  5331.     l1 length: 100.
  5332.     l1 origin moveTo: 10@10.
  5333.     self addConstraints.! !
  5334.  
  5335. !GrandStaffGlyph methodsFor: 'access'!
  5336. score: aScore
  5337.  
  5338.     score _ aScore.!
  5339. staffIndex: aNumber
  5340.  
  5341.     staffIndex _ aNumber.!
  5342. timeScale
  5343.  
  5344.     ^timeScale value!
  5345. timeScale: aNumber
  5346.  
  5347.     timeScale setValue: aNumber.!
  5348. timeScaleVar
  5349.  
  5350.     ^timeScale!
  5351. width
  5352.  
  5353.     ^l1 lengthVar value!
  5354. width: aNumber
  5355.  
  5356.     l1 lengthVar setValue: aNumber.!
  5357. widthVar
  5358.  
  5359.     ^l1 lengthVar! !
  5360.  
  5361. !GrandStaffGlyph methodsFor: 'glyph protocol'!
  5362. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  5363.  
  5364.     | scale timeChunk myStart myEnd xOrigin yOrigin blit t i last n |
  5365.     scale _ timeScale value.
  5366.     timeChunk _ (self width - 10) * scale.
  5367.     myStart _ staffIndex * timeChunk.
  5368.     myEnd _ myStart + timeChunk.
  5369.     xOrigin _ aDisplayPoint x + leftBar p1 x + 5.
  5370.     yOrigin _ aDisplayPoint y + leftBar p1 y + (45 * 2) - 1.
  5371.     blit _ BitBlt
  5372.         destForm: aDisplayMedium
  5373.         sourceForm: nil
  5374.         halftoneForm: (Form black)
  5375.         combinationRule: (Form over)
  5376.         destOrigin: (xOrigin@yOrigin)
  5377.         sourceOrigin: (0@0)
  5378.         extent: (2@3)
  5379.         clipRect: clipBox.
  5380.     i _ self indexFor: myStart.
  5381.     last _ self indexFor: myEnd + 1.
  5382.     [i < last] whileTrue:
  5383.         [n _ score at: i.
  5384.          t _ n start.
  5385.          blit destOrigin: (xOrigin + ((t - myStart) // scale))@(yOrigin - (n pitch * 2)).
  5386.          blit copyBits.
  5387.          i _ i + 1].!
  5388. indexFor: aTime
  5389.     "Answer the score index for the given time, assuming that the score is sorted in ascending time order."
  5390.  
  5391.     | lower upper middle |
  5392.     lower _ 1.
  5393.     upper _ score size.
  5394.     [lower < upper] whileTrue:
  5395.         [middle _ (lower + upper) // 2.
  5396.          ((score at: middle) start < aTime)
  5397.             ifTrue: [lower _ middle + 1]
  5398.             ifFalse: [upper _ middle]].
  5399.     ^lower!
  5400. locationPoints
  5401.  
  5402.     ^Array with: l1 origin!
  5403. OLDdisplayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  5404.  
  5405.     | scale timeChunk myStart myEnd xOrigin yOrigin blit t |
  5406.     scale _ timeScale value.
  5407.     timeChunk _ (self width - 10) * scale.
  5408.     myStart _ staffIndex * timeChunk.
  5409.     myEnd _ myStart + timeChunk.
  5410.     xOrigin _ aDisplayPoint x + leftBar p1 x + 5.
  5411.     yOrigin _ aDisplayPoint y + leftBar p1 y + (45 * 2) - 1.
  5412.     blit _ BitBlt
  5413.         destForm: aDisplayMedium
  5414.         sourceForm: nil
  5415.         halftoneForm: (Form black)
  5416.         combinationRule: (Form over)
  5417.         destOrigin: (xOrigin@yOrigin)
  5418.         sourceOrigin: (0@0)
  5419.         extent: (2@3)
  5420.         clipRect: clipBox.
  5421.     score do:
  5422.         [: n |
  5423.          t _ n start.
  5424.          ((t >= myStart) and: [t <= myEnd]) ifTrue:
  5425.             [blit destOrigin: (xOrigin + ((t - myStart) // scale))@(yOrigin - (n pitch * 2)).
  5426.              blit copyBits]].!
  5427. selectableGlyphsDo: aBlock
  5428.     "I have none."! !
  5429.  
  5430. !PointGlyph methodsFor: 'initialize-release'!
  5431. initialize
  5432.  
  5433.     | dotForm |
  5434.     super initialize.
  5435.     x _ FreeVariable value: 30.
  5436.     y _ FreeVariable value: 30.
  5437.     (Blt isNil) ifTrue:
  5438.         [dotForm _ (Form dotOfSize: 4) offset: 0@0.
  5439.          Blt _ BitBlt 
  5440.             destForm: Display                    "updated later"
  5441.             sourceForm: dotForm
  5442.             halftoneForm: (Form black)
  5443.             combinationRule: (Form under)
  5444.             destOrigin: 0@0                    "updated later"
  5445.             sourceOrigin: 0@0
  5446.             extent: (dotForm boundingBox extent)
  5447.             clipRect: (Display boundingBox)].     "updated later"!
  5448. setX: xVariable setY: yVariable
  5449.     "Used to create points out of variables."
  5450.  
  5451.     x _ xVariable.
  5452.     y _ yVariable.! !
  5453.  
  5454. !PointGlyph methodsFor: 'accessing'!
  5455. x
  5456.  
  5457.     ^x value!
  5458. x: aNumber
  5459.  
  5460.     x setValue: aNumber!
  5461. xVar
  5462.  
  5463.     ^x!
  5464. y
  5465.  
  5466.     ^y value!
  5467. y: aNumber
  5468.  
  5469.     y setValue: aNumber!
  5470. yVar
  5471.  
  5472.     ^y! !
  5473.  
  5474. !PointGlyph methodsFor: 'point protocol'!
  5475. * aPoint
  5476.  
  5477.     ^(self x * aPoint x)@(self y * aPoint y)!
  5478. + aPoint
  5479.  
  5480.     ^(self x + aPoint x)@(self y + aPoint y)!
  5481. - aPoint
  5482.  
  5483.     ^(self x - aPoint x)@(self y - aPoint y)!
  5484. / aPoint
  5485.  
  5486.     ^(self x / aPoint x)@(self y / aPoint y)!
  5487. asFloat
  5488.  
  5489.     ^x value asFloat@y value asFloat!
  5490. asPoint
  5491.  
  5492.     ^x value@y value!
  5493. max: aPoint
  5494.  
  5495.     ^(self x max: aPoint x)@(self y max: aPoint y)!
  5496. min: aPoint
  5497.  
  5498.     ^(self x min: aPoint x)@(self y min: aPoint y)!
  5499. rounded
  5500.  
  5501.     ^self asPoint rounded! !
  5502.  
  5503. !PointGlyph methodsFor: 'glyph protocol'!
  5504. boundingBox
  5505.  
  5506.     ^(self rounded - (3@3)) extent: 6@6!
  5507. containsPoint: aPoint
  5508.     "Points are such a common case that it pays to optimize. Thus, we compute the Manhattan distance (i.e. delta x + delta y) between this given point and our location and answer 'true' if the given point is close enough."
  5509.  
  5510.     ^((x value rounded - aPoint x) abs + (y value rounded - aPoint y) abs) < 8!
  5511. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  5512.  
  5513.     Blt
  5514.         destForm: aDisplayMedium;
  5515.         destOrigin:
  5516.             ((aDisplayPoint x rounded + x value - 2)@
  5517.              (aDisplayPoint y rounded + y value - 2));
  5518.         clipRect: clipBox;
  5519.         copyBits.!
  5520. isSelectable
  5521.  
  5522.     ^true!
  5523. locationPoints
  5524.  
  5525.     ^Array with: self! !
  5526.  
  5527. !PointGlyph methodsFor: 'merging'!
  5528. canMergeWith: aGlyph
  5529.  
  5530.     ^(self ~~ aGlyph) and:
  5531.      [(aGlyph isKindOf: PointGlyph) and:
  5532.      [aGlyph changing not]]!
  5533. mergeWith: aPointGlyph
  5534.  
  5535.     MergeConstraint merge: x with: (aPointGlyph xVar) strength: #strongPreferred.
  5536.     MergeConstraint merge: y with: (aPointGlyph yVar) strength: #strongPreferred.! !
  5537.  
  5538. !PointGlyph methodsFor: 'printing'!
  5539. printOn: aStream
  5540.  
  5541.     x printOn: aStream.
  5542.     aStream nextPutAll: '@'.
  5543.     y printOn: aStream.! !
  5544.  
  5545. !WiringNodeGlyph methodsFor: 'mouse'!
  5546. handleMouseDown: mousePoint view: aView
  5547.  
  5548.     | newLine |
  5549.     (Sensor leftShiftDown)
  5550.         ifTrue:
  5551.             [newLine _ WireGlyph new.
  5552.              (aView model) addGlyph: newLine.
  5553.              newLine p1 mergeWith: self.
  5554.              newLine p2 moveTo: self + (8@8).
  5555.              Sensor cursorPoint: aView insetDisplayBox origin + self + (8@8).
  5556.              aView controller
  5557.                 while: [Sensor anyButtonPressed]
  5558.                 move: (Array with: newLine p2)
  5559.                 refPoint: Sensor cursorPoint
  5560.                 mergeWith: newLine p2]
  5561.         ifFalse:
  5562.             [aView controller
  5563.                 while: [Sensor anyButtonPressed]
  5564.                 move: (Array with: self)
  5565.                 refPoint: Sensor cursorPoint
  5566.                 mergeWith: self]!
  5567. wantsMouse
  5568.  
  5569.     ^true! !
  5570.  
  5571. !InvisibleWiringNodeGlyph methodsFor: 'glyph protocol'!
  5572. isVisible
  5573.  
  5574.     ^false! !
  5575.  
  5576. !SIGGRAPHAnchorGlyph methodsFor: 'glyph protocol'!
  5577. boundingBox
  5578.  
  5579.     ^(self rounded - (4@3)) extent: 6@6!
  5580. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  5581.     AnchorForm
  5582.         displayOn: aDisplayMedium
  5583.         at: aDisplayPoint + self asPoint
  5584.         clippingBox: clipBox
  5585.         rule: Form paint
  5586.         mask: Form black! !
  5587.  
  5588. !SIGGRAPHAnchorGlyph methodsFor: 'merging'!
  5589. canMergeWith: aGlyph 
  5590.     ^false!
  5591. changing
  5592.     "This is a hack to prevent the ugly black can-merge box from showing up around 
  5593.     my anchor."
  5594.  
  5595.     ^true! !
  5596.  
  5597. !PaintablePointGlyph methodsFor: 'initialize-release'!
  5598. initialize
  5599.  
  5600.     | dotForm |
  5601.     super initialize.
  5602.     painted _ FreeVariable value: false.
  5603.     (LittleDotBlt isNil) ifTrue:
  5604.         [dotForm _ (Form dotOfSize: 2) offset: 0@0.
  5605.          LittleDotBlt _ BitBlt 
  5606.             destForm: Display                    "updated later"
  5607.             sourceForm: dotForm
  5608.             halftoneForm: (Form black)
  5609.             combinationRule: (Form under)
  5610.             destOrigin: 0@0                    "updated later"
  5611.             sourceOrigin: 0@0
  5612.             extent: (dotForm boundingBox extent)
  5613.             clipRect: (Display boundingBox)].     "updated later"! !
  5614.  
  5615. !PaintablePointGlyph methodsFor: 'accessing'!
  5616. painted
  5617.  
  5618.     ^painted value!
  5619. painted: aBoolean
  5620.  
  5621.     painted setValue: aBoolean.!
  5622. paintedVar
  5623.  
  5624.     ^painted! !
  5625.  
  5626. !PaintablePointGlyph methodsFor: 'glyph protocol'!
  5627. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  5628.  
  5629.     (painted value)
  5630.         ifTrue:
  5631.             [Blt
  5632.                 destForm: aDisplayMedium;
  5633.                 destOrigin:
  5634.                     ((aDisplayPoint x rounded + x value - 2)@
  5635.                      (aDisplayPoint y rounded + y value - 2));
  5636.                 clipRect: clipBox;
  5637.                 copyBits]
  5638.         ifFalse:
  5639.             [LittleDotBlt
  5640.                 destForm: aDisplayMedium;
  5641.                 destOrigin:
  5642.                     ((aDisplayPoint x rounded + x value - 1)@
  5643.                      (aDisplayPoint y rounded + y value - 1));
  5644.                 clipRect: clipBox;
  5645.                 copyBits]! !
  5646.  
  5647. !PaintablePointGlyph methodsFor: 'merging'!
  5648. canMergeWith: aGlyph
  5649.  
  5650.     ^false! !
  5651.  
  5652. !LabeledPointGlyph methodsFor: 'initialize-release'!
  5653. initialize
  5654.  
  5655.     super initialize.
  5656.     label _ FreeVariable new.! !
  5657.  
  5658. !LabeledPointGlyph methodsFor: 'accessing'!
  5659. label
  5660.  
  5661.     ^label value!
  5662. label: anObject
  5663.  
  5664.     label setValue: anObject.!
  5665. labelVar
  5666.  
  5667.     ^label! !
  5668.  
  5669. !LabeledPointGlyph methodsFor: 'merging'!
  5670. canMergeWith: aGlyph
  5671.  
  5672.     ^(self ~~ aGlyph) and:
  5673.      [(aGlyph class == self class) and:
  5674.      [aGlyph changing not]]!
  5675. mergeWith: aGlyph
  5676.  
  5677.     MergeConstraint merge: x with: (aGlyph xVar) strength: #strongPreferred.
  5678.     MergeConstraint merge: y with: (aGlyph yVar) strength: #strongPreferred.
  5679.     MergeConstraint merge: label with: (aGlyph labelVar) strength: #strongPreferred.! !
  5680.  
  5681. !SpringNodeGlyph methodsFor: 'initialize-release'!
  5682. initialize
  5683.  
  5684.     super initialize.
  5685.     force _ FreeVariable value: 0@0.! !
  5686.  
  5687. !SpringNodeGlyph methodsFor: 'accessing'!
  5688. force
  5689.  
  5690.     ^force value!
  5691. force: aPoint
  5692.  
  5693.     force setValue: aPoint!
  5694. forceVar
  5695.  
  5696.     ^force! !
  5697.  
  5698. !SpringNodeGlyph methodsFor: 'merging'!
  5699. canMergeWith: aGlyph
  5700.  
  5701.     ^(self ~~ aGlyph) and:
  5702.      [(aGlyph class == SpringNodeGlyph) and:
  5703.      [aGlyph changing not]]!
  5704. mergeWith: aGlyph
  5705.  
  5706.     MergeConstraint merge: x with: (aGlyph xVar) strength: #strongPreferred.
  5707.     MergeConstraint merge: y with: (aGlyph yVar) strength: #strongPreferred.
  5708.     MergeConstraint merge: label with: (aGlyph labelVar) strength: #strongPreferred.
  5709.     MergeConstraint merge: force with: (aGlyph forceVar) strength: #strongPreferred.! !
  5710.  
  5711. !SpringNodeGlyph methodsFor: 'mouse'!
  5712. handleMouseDown: mousePoint view: aView
  5713.  
  5714.     | newRod |
  5715.     (Sensor leftShiftDown)
  5716.         ifTrue:
  5717.             [newRod _ SpringGlyph new.
  5718.              (aView model) addGlyph: newRod.
  5719.              newRod p1 mergeWith: self.
  5720.              newRod p2 moveTo: self + (8@8).
  5721.              Sensor cursorPoint: aView insetDisplayBox origin + self + (8@8).
  5722.              aView controller
  5723.                 while: [Sensor anyButtonPressed]
  5724.                 move: (Array with: newRod p2)
  5725.                 refPoint: Sensor cursorPoint
  5726.                 mergeWith: newRod p2]
  5727.         ifFalse:
  5728.             [aView controller
  5729.                 while: [Sensor anyButtonPressed]
  5730.                 move: (Array with: self)
  5731.                 refPoint: Sensor cursorPoint
  5732.                 mergeWith: self]!
  5733. wantsMouse
  5734.  
  5735.     ^true! !
  5736.  
  5737. !PlanetGlyph methodsFor: 'initialize-release'!
  5738. initialize
  5739.     super initialize.
  5740.     form _ Form dotOfSize: 5! !
  5741.  
  5742. !PlanetGlyph methodsFor: 'accessing'!
  5743. form1
  5744.     self form: (DefaultForms at: 1)!
  5745. form2
  5746.     self form: (DefaultForms at: 2)!
  5747. form2b
  5748.     self form: (DefaultForms at: 4)!
  5749. form3
  5750.     self form: (DefaultForms at: 3)!
  5751. form: f 
  5752.     form _ f.
  5753.     form offset: (form width // 2) negated @ (form height // 2) negated! !
  5754.  
  5755. !PlanetGlyph methodsFor: 'glyph protocol'!
  5756. boundingBox
  5757.     | offset |
  5758.     offset _ form boundingBox extent // 2.
  5759.     offset _ offset x negated @ offset y negated.
  5760.     ^(form boundingBox copy translateBy: self asPoint)
  5761.         translateBy: offset!
  5762. containsPoint: aPoint 
  5763.     ^self boundingBox containsPoint: aPoint!
  5764. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  5765.     form
  5766.         displayOn: aDisplayMedium
  5767.         at: aDisplayPoint x + x value rounded @ (aDisplayPoint y + y value rounded)
  5768.         clippingBox: clipBox! !
  5769.  
  5770. !PlanetGlyph methodsFor: 'enumeration'!
  5771. selectableGlyphsDo: aBlock 
  5772.     aBlock value: self.!
  5773. visibleGlyphsDo: aBlock 
  5774.     aBlock value: self.! !
  5775.  
  5776. !FakeMouseGlyph methodsFor: 'glyph protocol'!
  5777. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  5778.     MouseForm
  5779.         displayOn: aDisplayMedium
  5780.         at: aDisplayPoint + self asPoint
  5781.         clippingBox: clipBox
  5782.         rule: Form paint
  5783.         mask: Form black! !
  5784.  
  5785. !FakeMouseGlyph methodsFor: 'merging'!
  5786. canMergeWith: aGlyph 
  5787.     ^false!
  5788. changing
  5789.     "This is a hack to prevent the ugly black can-merge box from showing up around 
  5790.     my anchor."
  5791.  
  5792.     ^true! !
  5793.  
  5794. !InvisiblePointGlyph methodsFor: 'glyph protocol'!
  5795. isSelectable
  5796.  
  5797.     ^false!
  5798. isVisible
  5799.  
  5800.     ^false! !
  5801.  
  5802. !MacDrawDraggerGlyph methodsFor: 'initialize-release'!
  5803. initialize
  5804.     self initialize: '?'!
  5805. initialize: i
  5806.     super initialize.
  5807.     exists _ FreeVariable value: true.! !
  5808.  
  5809. !MacDrawDraggerGlyph methodsFor: 'accessing'!
  5810. dash
  5811.     ^myDash!
  5812. dash: d scene: s 
  5813.     myDash _ d.
  5814.     theScene _ s!
  5815. exists
  5816.     ^exists!
  5817. height
  5818.     ^y!
  5819. isSpare
  5820.     ^exists value and: [myDash exists value not]!
  5821. offset
  5822.     ^x! !
  5823.  
  5824. !MacDrawDraggerGlyph methodsFor: 'glyph protocol'!
  5825. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  5826.     | p box |
  5827.     exists value
  5828.         ifTrue: 
  5829.             [self
  5830.                 vLineFrom: x value @ MacDrawDemo dragTop
  5831.                 length: MacDrawDemo dragBottom - MacDrawDemo dragTop
  5832.                 on: aDisplayMedium
  5833.                 at: aDisplayPoint
  5834.                 clip: clipBox.
  5835.             "box _ MacDrawDemo dragBox.  
  5836.             p _ self asPoint - (box width // 2 @ (box height // 2)) + 
  5837.             aDisplayPoint.  
  5838.             box moveTo: p.  
  5839.             aDisplayMedium fill: box mask: Form white.  
  5840.             aDisplayMedium border: box width: 1"
  5841.             MacDrawDemo draggerBoxForm displayOn: aDisplayMedium at: aDisplayPoint + self asPoint]!
  5842. isSelectable
  5843.     ^exists value!
  5844. isVisible
  5845.     ^true!
  5846. locationPoints
  5847.     ^Array with: self! !
  5848.  
  5849. !MacDrawDraggerGlyph methodsFor: 'printing'!
  5850. printOn: aStream 
  5851.     | title |
  5852.     title _ self class name.
  5853.     aStream nextPutAll: ((title at: 1) isVowel
  5854.                             ifTrue: ['an ']
  5855.                             ifFalse: ['a '])
  5856.                         , title! !
  5857.  
  5858. !MacDrawDraggerGlyph methodsFor: 'mouse'!
  5859. handleMouseDown: mousePoint view: view 
  5860.     Cursor execute
  5861.         showWhile: 
  5862.             [editConstraints _ theScene editConstraintsFor: self and: myDash.
  5863.             plan _ Planner extractPlanFromInputConstraints: editConstraints.
  5864.             view computeBackground]!
  5865. handleMouseMove: mousePoint view: view
  5866. "MessageTally spyOn: [
  5867. 1 to: 10 do: [:i |"
  5868.     plan execute.
  5869.     view displayFeedback
  5870. "]]"!
  5871. handleMouseUp: mousePoint view: view 
  5872.     Cursor execute
  5873.         showWhile: 
  5874.             [editConstraints do: [:each | each destroyConstraint].
  5875.             editConstraints _ nil.
  5876.             plan release.
  5877.             plan _ nil.
  5878.             theScene cleanUpFor: self and: myDash.
  5879.             view displayScene]!
  5880. wantsMouse
  5881.     ^true! !
  5882.  
  5883. !MacDrawDraggerGlyph methodsFor: 'scene access'!
  5884. doDashDraggerAlignDefault: idx 
  5885.     "The default alignment is to keep them aligned.  However, if the dash 
  5886.     does not exist, then don't bother."
  5887.  
  5888.     myFlexiConstraint notNil
  5889.         ifTrue: 
  5890.             [myFlexiConstraint destroyConstraint.
  5891.             myFlexiConstraint _ nil].
  5892.     myDash exists value ifTrue: [myFlexiConstraint _ (FlexiEqualityConstraint
  5893.                     var: myDash right0
  5894.                     var: self offset
  5895.                     strength: #default)
  5896.                     name: idx printString , ':dash right0 = drag offset']!
  5897. doDashDraggerAlignMovement: idx 
  5898.     "When moving the last dragger, we use a different constraint."
  5899.  
  5900.     myFlexiConstraint notNil
  5901.         ifTrue: 
  5902.             [myFlexiConstraint destroyConstraint.
  5903.             myFlexiConstraint _ nil].
  5904.     CopyConstraint isNil ifTrue: [CopyConstraint _
  5905.             Constraint names: #(a b) methods: #('a _ b')].
  5906.     myFlexiConstraint _ ("FlexiEqualityConstraint"
  5907.                         CopyConstraint copy
  5908.                 var: self offset
  5909.                 var: myDash right1
  5910.                 strength: #required)
  5911.                 name: idx printString , ':dragger = right1'! !
  5912.  
  5913. !AnchorGlyph methodsFor: 'initialize-release'!
  5914. initialize
  5915.  
  5916.     super initialize.
  5917.     node _ SpringNodeGlyph new.
  5918.     anchorForm _ FormGlyph new form:
  5919.         (Form
  5920.             extent: 17@20
  5921.             fromArray: #(480 0 480 0 480 0 480 0 192 0 192 0 192 0 192 0 192 0 192 0 192 0 192 0 24769 32768 28867 32768 30919 32768 15567 0 6342 0 3276 0 2040 0 1008 0)
  5922.             offset: 0@0).
  5923.     OffsetConstraint fromPoint: (node) to: (anchorForm center) require: -1@8.! !
  5924.  
  5925. !AnchorGlyph methodsFor: 'glyph protocol'!
  5926. boundingBox
  5927.  
  5928.     ^anchorForm boundingBox merge: node boundingBox!
  5929. locationPoints
  5930.  
  5931.     ^node locationPoints!
  5932. selectableGlyphsDo: aBlock
  5933.  
  5934.     node selectableGlyphsDo: aBlock! !
  5935.  
  5936. !AnchorGlyph methodsFor: 'accessing'!
  5937. node
  5938.  
  5939.     ^node! !
  5940.  
  5941. !AnchorGlyph methodsFor: 'initialize-release'!
  5942. initialize
  5943.  
  5944.     super initialize.
  5945.     node _ SpringNodeGlyph new.
  5946.     anchorForm _ FormGlyph new form:
  5947.         (Form
  5948.             extent: 17@20
  5949.             fromArray: #(480 0 480 0 480 0 480 0 192 0 192 0 192 0 192 0 192 0 192 0 192 0 192 0 24769 32768 28867 32768 30919 32768 15567 0 6342 0 3276 0 2040 0 1008 0)
  5950.             offset: 0@0).
  5951.     OffsetConstraint fromPoint: (node) to: (anchorForm center) require: -1@8.! !
  5952.  
  5953. !AnchorGlyph methodsFor: 'glyph protocol'!
  5954. boundingBox
  5955.  
  5956.     ^anchorForm boundingBox merge: node boundingBox!
  5957. locationPoints
  5958.  
  5959.     ^node locationPoints!
  5960. selectableGlyphsDo: aBlock
  5961.  
  5962.     node selectableGlyphsDo: aBlock! !
  5963.  
  5964. !AnchorGlyph methodsFor: 'accessing'!
  5965. node
  5966.  
  5967.     ^node! !
  5968.  
  5969. !SpringGlyph methodsFor: 'initialize-release'!
  5970. addConstraints
  5971.  
  5972.     "note: a positive force means an outward push"
  5973.     (ForceC == nil) ifTrue:
  5974.         [ForceC _ Constraint
  5975.             names: #(force k length p1x p1y p2x p2y)
  5976.             methods: #('force _ k * (length - ((p1x - p2x)@(p1y - p2y)) r) asFloat')].
  5977.     (ForceC copy)
  5978.         var: (force) var: (springConstant) var: (nominalLength)
  5979.         var: (p1 xVar) var: (p1 yVar)
  5980.         var: (p2 xVar) var: (p2 yVar)
  5981.         strength: #required.!
  5982. initialize
  5983.  
  5984.     super initialize.
  5985.     p1 _ SpringNodeGlyph new moveTo: 10@10.
  5986.     p2 _ SpringNodeGlyph new moveTo: 10@70.
  5987.     nominalLength _ FreeVariable value: 60.
  5988.     springConstant _ FreeVariable value: 5.0.
  5989.     force _ FreeVariable new.
  5990.     self addConstraints.! !
  5991.  
  5992. !SpringGlyph methodsFor: 'accessing'!
  5993. force
  5994.  
  5995.     ^force value!
  5996. forceVar
  5997.  
  5998.     ^force!
  5999. p1
  6000.  
  6001.     ^p1!
  6002. p2
  6003.  
  6004.     ^p2! !
  6005.  
  6006. !SpringGlyph methodsFor: 'glyph protocol'!
  6007. boundingBox
  6008.  
  6009.     ^p1 boundingBox merge: p2 boundingBox!
  6010. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6011.     "Display the line connecting my endpoints."
  6012.  
  6013.     self
  6014.         lineFrom: p1
  6015.         to: p2
  6016.         on: aDisplayMedium
  6017.         at: aDisplayPoint
  6018.         clip: clipBox.!
  6019. isSelectable
  6020.  
  6021.     ^false!
  6022. locationPoints
  6023.  
  6024.     ^Array with: p1 with: p2! !
  6025.  
  6026. !MacDrawDashGlyph methodsFor: 'initialize-release'!
  6027. initialize
  6028.     self initialize: '?'!
  6029. initialize: i 
  6030.     "MacDrawDashGlyph releaseConstraints"
  6031.  
  6032.     super initialize.
  6033.     left0 _ FreeVariable value: 10.
  6034.     left1 _ FreeVariable value: 10.
  6035.     left2 _ FreeVariable value: 10.
  6036.     left3 _ FreeVariable value: 10.
  6037.     right0 _ FreeVariable value: 50.
  6038.     right1 _ FreeVariable value: 50.
  6039.     right2 _ FreeVariable value: 50.
  6040.     right3 _ FreeVariable value: 50.
  6041.     length0 _ FreeVariable value: 40.
  6042.     length1 _ FreeVariable value: 40.
  6043.     length2 _ FreeVariable value: 40.
  6044.     length3 _ FreeVariable value: 40.
  6045.     color _ FreeVariable value: true.
  6046.     exists _ FreeVariable value: true.
  6047.     LengthConstraint isNil ifTrue: [LengthConstraint _ Constraint names: #(left length right ) methods: #('right _ left + length' 'length _ right - left' 'left _ right - length' )].
  6048.     (LengthConstraint copy
  6049.         var: left3
  6050.         var: length3
  6051.         var: right3
  6052.         strength: #required)
  6053.         name: i printString , ':dash length3 = left3 - right3'.
  6054.     (LengthConstraint copy
  6055.         var: left2
  6056.         var: length2
  6057.         var: right2
  6058.         strength: #required)
  6059.         name: i printString , ':dash length2 = left2 - right2'.
  6060.     (LengthConstraint copy
  6061.         var: left1
  6062.         var: length1
  6063.         var: right1
  6064.         strength: #required)
  6065.         name: i printString , ':dash length1 = left1 - right1'.
  6066.     (LengthConstraint copy
  6067.         var: left0
  6068.         var: length0
  6069.         var: right0
  6070.         strength: #required)
  6071.         name: i printString , ':dash length0 = left0 - right0'! !
  6072.  
  6073. !MacDrawDashGlyph methodsFor: 'accessing'!
  6074. color
  6075.     ^color!
  6076. exists
  6077.     ^exists!
  6078. left
  6079.     ^self halt: 'use a different left'!
  6080. left0 ^left0!
  6081. left1 ^left1!
  6082. left2 ^left2!
  6083. left3 ^left3!
  6084. length
  6085.     ^self halt: 'use different length'!
  6086. length0 ^length0!
  6087. length1 ^length1!
  6088. length2 ^length2!
  6089. length3 ^length3!
  6090. right
  6091.     ^self halt: 'use different right'!
  6092. right0 ^right0!
  6093. right1 ^right1!
  6094. right2 ^right2!
  6095. right3 ^right3! !
  6096.  
  6097. !MacDrawDashGlyph methodsFor: 'glyph protocol'!
  6098. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  6099.     | box |
  6100.     exists value
  6101.         ifTrue: 
  6102.             [box _ left0 value @ MacDrawDemo dashTop corner: right0 value @ MacDrawDemo dashBottom.
  6103.             box translateBy: aDisplayPoint.
  6104.             color value
  6105.                 ifTrue: [aDisplayMedium fill: box mask: Form black]
  6106.                 ifFalse: 
  6107.                     ["aDisplayMedium border: box width: 1."
  6108.                     self
  6109.                         hLineFrom: left0 value rounded @ MacDrawDemo dashTop
  6110.                         length: length0 value rounded
  6111.                         on: aDisplayMedium
  6112.                         at: aDisplayPoint
  6113.                         clip: clipBox.
  6114.                     self
  6115.                         hLineFrom: left0 value rounded @ (MacDrawDemo dashBottom - 1)
  6116.                         length: length0 value rounded
  6117.                         on: aDisplayMedium
  6118.                         at: aDisplayPoint
  6119.                         clip: clipBox]]!
  6120. locationPoints
  6121.     ^Array with: left0 value + right0 value // 2 @ (MacDrawDemo dashTop + MacDrawDemo dashBottom // 2)! !
  6122.  
  6123. !FormGlyph methodsFor: 'initialize-release'!
  6124. initialize
  6125.  
  6126.     super initialize.
  6127.     center _ InvisiblePointGlyph new moveTo: 30@30.
  6128.     form _ (Form
  6129.         extent: 8@10
  6130.         fromArray: #(15360 16896 33024 40192 37120 39168 37120 37120 16896 15360)
  6131.         offset: 0@0).! !
  6132.  
  6133. !FormGlyph methodsFor: 'accessing'!
  6134. center
  6135.  
  6136.     ^center!
  6137. form
  6138.  
  6139.     ^form!
  6140. form: aForm
  6141.  
  6142.     form _ aForm.! !
  6143.  
  6144. !FormGlyph methodsFor: 'glyph protocol'!
  6145. boundingBox
  6146.  
  6147.     ^self formBox insetOriginBy: -1@-1 cornerBy: -1@-1!
  6148. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  6149.  
  6150.     self form
  6151.         displayOn: aDisplayMedium
  6152.         at: (aDisplayPoint + self formOffset)
  6153.         clippingBox: clipBox
  6154.         rule: (Form paint)
  6155.         mask: (Form black).!
  6156. isSelectable
  6157.  
  6158.     ^true!
  6159. locationPoints
  6160.  
  6161.     ^Array with: center! !
  6162.  
  6163. !FormGlyph methodsFor: 'private'!
  6164. formBox
  6165.     "Answer my form bounding box."
  6166.  
  6167.     ^self form computeBoundingBox translateBy: self formOffset!
  6168. formOffset
  6169.     "Center my form on my center."
  6170.  
  6171.     ^center - (self form extent // 2)!
  6172. initializeWith: aForm
  6173.  
  6174.     super initialize.
  6175.     center _ InvisiblePointGlyph new moveTo: 30@30.
  6176.     form _ aForm.! !
  6177.  
  6178. IconGlyph comment:
  6179. 'I am an abstract class for a special kind of Glyph that displays an icon with a centered text label below it. My subclasses must respond to these messages:
  6180.     name
  6181.     name:
  6182.     icon
  6183.     icon:
  6184.  
  6185. I cache a Form for my name in the instance variable ''nameForm'' for more efficient display. My subclasses must update this cache whenever their name changes by sending me the message updateNameIcon.'!
  6186.  
  6187. !IconGlyph methodsFor: 'initialize-release'!
  6188. initialize
  6189.  
  6190.     super initialize.
  6191.     self name: 'An Icon Glyph'.! !
  6192.  
  6193. !IconGlyph methodsFor: 'accessing'!
  6194. name
  6195.  
  6196.     ^name!
  6197. name: aString
  6198.     "For efficiency, I cache a Form containing the bitmap for the text of my name."
  6199.  
  6200.     name _ aString.
  6201.     nameForm _
  6202.         (Paragraph
  6203.             withText: self name asText
  6204.             style: ((TextStyle default) lineGrid: 12; baseline: 9))
  6205.                 centered asForm.! !
  6206.  
  6207. !IconGlyph methodsFor: 'glyph protocol'!
  6208. boundingBox
  6209.     "Answer my bounding box."
  6210.  
  6211.     ^self formBox merge: self nameBox!
  6212. containsPoint: aPoint
  6213.     "Answer true if either my icon or name boxes contains the given point. Allow a little slop around the icon box."
  6214.  
  6215.     ^(((self formBox) expandBy: 2) containsPoint: aPoint) or:
  6216.       [(self nameBox) containsPoint: aPoint]!
  6217. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6218.  
  6219.     self form
  6220.         displayOn: aDisplayMedium
  6221.         at: (aDisplayPoint + self formOffset)
  6222.         clippingBox: clipBox
  6223.         rule: (Form over)
  6224.         mask: (Form black).
  6225.  
  6226.     nameForm
  6227.         displayOn: aDisplayMedium
  6228.         at: (aDisplayPoint + self nameOffset)
  6229.         clippingBox: clipBox
  6230.         rule: (Form over)
  6231.         mask: (Form black).!
  6232. highlightOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6233.  
  6234.     aDisplayMedium
  6235.         border: ((self formBox translateBy: aDisplayPoint) expandBy: 1)
  6236.         widthRectangle: (1@1 corner: 1@1)
  6237.         mask: (Form gray)
  6238.         clippingBox: clipBox.! !
  6239.  
  6240. !IconGlyph methodsFor: 'private'!
  6241. nameBox
  6242.     "Answer my name bounding box."
  6243.  
  6244.     ^nameForm computeBoundingBox translateBy: self nameOffset!
  6245. nameOffset
  6246.     "Center my nameForm under my form."
  6247.  
  6248.     ^center +
  6249.         ((nameForm width negated // 2)@((self form height // 2) + 2))! !
  6250.  
  6251. !CapacitorGlyph methodsFor: 'initialize-release'!
  6252. initialize
  6253.  
  6254.     super initialize.
  6255.     p1 _ InvisibleWiringNodeGlyph new.
  6256.     p2 _ InvisibleWiringNodeGlyph new.
  6257.     OffsetConstraint fromPoint: p1 to: p2 require: 0@30.
  6258.     p1 moveTo: 10@10.
  6259.     form _ (Form
  6260.         extent: 13@30
  6261.         fromArray: #(512 512 512 512 512 512 512 512 512 512 512 512 16912 8736 6848 1792 0 32752 512 512 512 512 512 512 512 512 512 512 512 512)
  6262.         offset: 0@0)! !
  6263.  
  6264. !CapacitorGlyph methodsFor: 'glyph protocol'!
  6265. boundingBox
  6266.  
  6267.     ^form computeBoundingBox translateBy:  (p1 - (6@0))!
  6268. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6269.  
  6270.     form
  6271.         displayOn: aDisplayMedium
  6272.         at: (aDisplayPoint + (p1 - (6@0)))
  6273.         clippingBox: clipBox
  6274.         rule: (Form paint)
  6275.         mask: (Form black).!
  6276. isSelectable
  6277.  
  6278.     ^true!
  6279. locationPoints
  6280.  
  6281.     ^Array with: p1 with: p2! !
  6282.  
  6283. !ResistorGlyph methodsFor: 'initialize-release'!
  6284. initialize
  6285.  
  6286.     super initialize.
  6287.     form _ (Form
  6288.         extent: 13@30
  6289.         fromArray: #(512 512 512 512 512 512 3584 14336 3584 896 224 896 3584 14336 3584 896 224 896 3584 14336 3584 896 224 896 512 512 512 512 512 512)
  6290.         offset: 0@0).! !
  6291.  
  6292. !BezierGlyph methodsFor: 'initialize-release'!
  6293. initialize
  6294.  
  6295.     super initialize.
  6296.     p1 _ PointGlyph new moveTo: 10@10.
  6297.     p2 _ PointGlyph new moveTo: 40@10.
  6298.     p3 _ PointGlyph new moveTo: 25@25.
  6299.     p4 _ PointGlyph new moveTo: 35@25.
  6300.     p5 _ PointGlyph new moveTo: 40@40.
  6301.     p6 _ PointGlyph new moveTo: 30@50.
  6302.     showControl _ true.! !
  6303.  
  6304. !BezierGlyph methodsFor: 'glyph protocol'!
  6305. boundingBox
  6306.  
  6307.     | points min max extent |
  6308.     points _ self locationPoints.
  6309.     min _ points inject: p1 into: [: min : p | min min: p].
  6310.     max _ points inject: p1 into: [: max : p | max max: p].
  6311.     extent _ p1 boundingBox extent // 2.
  6312.     ^min - extent corner: max + extent!
  6313. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6314.     "Draw the lines connecting my vertices."
  6315.  
  6316.     (showControl) ifTrue:
  6317.         [self
  6318.             connectPoints: self locationPoints
  6319.             on: aDisplayMedium at: aDisplayPoint clip: clipBox
  6320.             penSize: 1@1].
  6321.     self
  6322.         connectPoints: (self computeBezierPointCount: 10)
  6323.         on: aDisplayMedium at: aDisplayPoint clip: clipBox
  6324.         penSize: 2@2.!
  6325. isSelectable
  6326.  
  6327.     ^Sensor leftShiftDown!
  6328. locationPoints
  6329.  
  6330.     ^(Array with: p1 with: p2 with: p3),
  6331.       (Array with: p4 with: p5 with: p6)! !
  6332.  
  6333. !BezierGlyph methodsFor: 'private'!
  6334. computeBezierPointCount: pointCount
  6335.  
  6336.     | controlPoints curvePoints stepSize step t oneMinusT scratch n |
  6337.     controlPoints _ self locationPoints collect: [: p | p x asFloat@p y asFloat].
  6338.     curvePoints _ OrderedCollection new: pointCount * 2.
  6339.     stepSize _ 1.0 / pointCount asFloat.
  6340.     step _ 0.0.
  6341.     (pointCount + 1) timesRepeat:
  6342.         [t _ step@step.
  6343.          oneMinusT _ (1.0 - step)@(1.0 - step).
  6344.          scratch _ controlPoints copy.
  6345.          n _ scratch size.
  6346.          [n > 1] whileTrue:
  6347.             [1 to: n - 1 do:
  6348.                 [: i |
  6349.                  scratch at: i put:
  6350.                     ((t * (scratch at: i)) + (oneMinusT * (scratch at: i + 1)))].
  6351.              n _ n - 1].
  6352.          curvePoints addLast: (scratch at: 1) rounded.
  6353.          step _ step + stepSize].
  6354.  
  6355.     ^curvePoints!
  6356. connectPoints: pointList on: aDisplayMedium at: aDisplayPoint clip: clipBox mask: mask
  6357.     "Draw the lines connecting the given set of points."
  6358.  
  6359.     | line |
  6360.     line _ Line
  6361.         from: 0@0
  6362.         to: 0@0
  6363.         withForm: ((Form extent: 1@1) black).
  6364.     1 to: pointList size - 1 do:
  6365.         [: i |
  6366.          line beginPoint: (pointList at: i) rounded.
  6367.          line endPoint: (pointList at: i + 1) rounded.
  6368.          line
  6369.             displayOn: aDisplayMedium
  6370.             at: aDisplayPoint
  6371.             clippingBox: clipBox
  6372.             rule: (Form over)
  6373.             mask: mask].!
  6374. connectPoints: pointList on: aDisplayMedium at: aDisplayPoint clip: clipBox penSize: penSize
  6375.     "Draw the lines connecting the given set of points."
  6376.  
  6377.     | line |
  6378.     line _ Line
  6379.         from: 0@0
  6380.         to: 0@0
  6381.         withForm: ((Form extent: penSize) black).
  6382.     1 to: pointList size - 1 do:
  6383.         [: i |
  6384.          line beginPoint: (pointList at: i) rounded.
  6385.          line endPoint: (pointList at: i + 1) rounded.
  6386.          line
  6387.             displayOn: aDisplayMedium
  6388.             at: aDisplayPoint
  6389.             clippingBox: clipBox
  6390.             rule: (Form paint)
  6391.             mask: (Form black)].! !
  6392.  
  6393. !TransistorGlyph methodsFor: 'initialize-release'!
  6394. initialize
  6395.  
  6396.     super initialize.
  6397.     base _ InvisibleWiringNodeGlyph new.
  6398.     emitter _ InvisibleWiringNodeGlyph new.
  6399.     collector _ InvisibleWiringNodeGlyph new.
  6400.     OffsetConstraint fromPoint: base to: emitter require: 25@-15.
  6401.     OffsetConstraint fromPoint: base to: collector require: 25@15.
  6402.     base moveTo: 10@10.
  6403.     form _ (Form
  6404.         extent: 28@29
  6405.         fromArray: #(0 256 0 512 0 1024 0 2048 31 61440 32 10240 64 17408 128 33280 273 256 530 128 1044 64 1048 64 1040 64 1040 64 65520 64 1040 64 1040 64 1048 64 1044 64 530 128 273 256 128 33280 64 17408 32 10240 31 61440 0 2048 0 1024 0 512 0 256)
  6406.         offset: 0@0).! !
  6407.  
  6408. !TransistorGlyph methodsFor: 'glyph protocol'!
  6409. boundingBox
  6410.  
  6411.     ^form computeBoundingBox translateBy:  (base - (0@15))!
  6412. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6413.  
  6414.     form
  6415.         displayOn: aDisplayMedium
  6416.         at: (aDisplayPoint + (base + (1@-14)))
  6417.         clippingBox: clipBox
  6418.         rule: (Form paint)
  6419.         mask: (Form black).!
  6420. isSelectable
  6421.  
  6422.     ^true!
  6423. locationPoints
  6424.  
  6425.     ^Array with: base with: emitter with: collector! !
  6426.  
  6427. !TriangleGlyph methodsFor: 'initialize-release'!
  6428. initialize
  6429.  
  6430.     super initialize.
  6431.     p1 _ PointGlyph new moveTo: 10@10.
  6432.     p2 _ PointGlyph new moveTo: 40@10.
  6433.     p3 _ PointGlyph new moveTo: 25@25.! !
  6434.  
  6435. !TriangleGlyph methodsFor: 'glyph protocol'!
  6436. boundingBox
  6437.  
  6438.     ^(p1 boundingBox merge: p2 boundingBox)
  6439.         merge: p3 boundingBox!
  6440. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6441.     "Draw the lines connecting my vertices."
  6442.  
  6443.     self
  6444.         lineFrom: p1 to: p2
  6445.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  6446.     self
  6447.         lineFrom: p2 to: p3
  6448.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  6449.     self
  6450.         lineFrom: p3 to: p1
  6451.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.!
  6452. locationPoints
  6453.  
  6454.     ^Array with: p1 with: p2 with: p3! !
  6455.  
  6456. !BasicRectangleGlyph methodsFor: 'initialize-release'!
  6457. initialize
  6458.  
  6459.     super initialize.
  6460.     center _ InvisiblePointGlyph new.
  6461.     left _ FreeVariable new.
  6462.     right _ FreeVariable new.
  6463.     top _ FreeVariable new.
  6464.     bottom _ FreeVariable new.
  6465.     width _ FreeVariable new value: 60.
  6466.     height _ FreeVariable value: 20.! !
  6467.  
  6468. !BasicRectangleGlyph methodsFor: 'accessing'!
  6469. asRectangle
  6470.     ^left value @ top value corner: right value @ bottom value!
  6471. bottom
  6472.  
  6473.     ^bottom value!
  6474. bottom: aNumber
  6475.  
  6476.     bottom setValue: aNumber.!
  6477. bottomLeft
  6478.     ^left value @ bottom value!
  6479. bottomRight
  6480.     ^right value @ bottom value!
  6481. bottomVar
  6482.  
  6483.     ^bottom!
  6484. center
  6485.     ^center!
  6486. corner
  6487.     ^self bottomRight!
  6488. extent
  6489.     ^self width @ self height!
  6490. height
  6491.  
  6492.     ^height value!
  6493. height: aNumber
  6494.  
  6495.     height setValue: aNumber.!
  6496. heightVar
  6497.  
  6498.     ^height!
  6499. left
  6500.  
  6501.     ^left value!
  6502. left: aNumber
  6503.  
  6504.     left setValue: aNumber.!
  6505. leftVar
  6506.  
  6507.     ^left!
  6508. origin
  6509.     ^self topLeft!
  6510. right
  6511.  
  6512.     ^right value!
  6513. right: aNumber
  6514.  
  6515.     right setValue: aNumber.!
  6516. rightVar
  6517.  
  6518.     ^right!
  6519. top
  6520.  
  6521.     ^top value!
  6522. top: aNumber
  6523.  
  6524.     top setValue: aNumber.!
  6525. topLeft
  6526.     ^left value @ top value!
  6527. topRight
  6528.     ^right value @ top value!
  6529. topVar
  6530.  
  6531.     ^top!
  6532. width
  6533.  
  6534.     ^width value!
  6535. width: aNumber
  6536.  
  6537.     width setValue: aNumber.!
  6538. widthVar
  6539.  
  6540.     ^width! !
  6541.  
  6542. !BasicRectangleGlyph methodsFor: 'glyph protocol'!
  6543. boundingBox
  6544.  
  6545.     ^(left value@top value) extent: (width value@height value)!
  6546. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6547.  
  6548.     aDisplayMedium
  6549.         border: (self boundingBox moveBy: aDisplayPoint)
  6550.         widthRectangle: (1@1 corner: 1@1)
  6551.         mask: (Form black)
  6552.         clippingBox: clipBox.!
  6553. isSelectable
  6554.  
  6555.     ^true!
  6556. locationPoints
  6557.  
  6558.     ^Array with: center! !
  6559.  
  6560. !BasicRectangleGlyph methodsFor: 'printing'!
  6561. printOn: aStream
  6562.  
  6563.     aStream nextPutAll:
  6564.         self class name, '(', center x printString, '@', center y printString, ')'.! !
  6565.  
  6566. !RectangleGlyph methodsFor: 'initialize-release'!
  6567. initialize
  6568.     "Adds constraints to update left/right/top/bottom/center. Width and height are fixed."
  6569.  
  6570.     super initialize.
  6571.     (CenterC == nil) ifTrue:
  6572.         [CenterC _ Constraint
  6573.             names: #(p1 p2 delta)
  6574.             methods: #(
  6575.                 'p1 _ p2 - (delta asFloat / 2) rounded'
  6576.                 'p2 _ p1 + ((delta asFloat / 2) + 0.5) rounded')].
  6577.     (CenterC copy) var: (left) var: (center xVar) var: (width) strength: #required.
  6578.     (CenterC copy) var: (center xVar) var: (right) var: (width) strength: #required.
  6579.     (CenterC copy) var: (top) var: (center yVar) var: (height) strength: #required.
  6580.     (CenterC copy) var: (center yVar) var: (bottom) var: (height) strength: #required.! !
  6581.  
  6582. !ArrowHeadGlyph methodsFor: 'initialize-release'!
  6583. initialize
  6584.  
  6585.     super initialize.
  6586.     location _ InvisiblePointGlyph new.
  6587.     vector _ InvisiblePointGlyph new moveTo: 10@10.! !
  6588.  
  6589. !ArrowHeadGlyph methodsFor: 'accessing'!
  6590. location
  6591.  
  6592.     ^location!
  6593. vector
  6594.  
  6595.     ^vector!
  6596. vector: vectorPoint
  6597.     "Set my vector. The vector is used to choose an arrowhead with the right orientation."
  6598.  
  6599.     vector moveTo: vectorPoint.! !
  6600.  
  6601. !ArrowHeadGlyph methodsFor: 'glyph protocol'!
  6602. boundingBox
  6603.     "Answer my bounding box."
  6604.  
  6605.     | form |
  6606.     form _ self form.
  6607.     ^form computeBoundingBox
  6608.          translateBy: (location asPoint + form offset)!
  6609. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6610.     "Display myself."
  6611.  
  6612.     self form
  6613.         displayOn: aDisplayMedium
  6614.         at: (aDisplayPoint + location)
  6615.         clippingBox: clipBox
  6616.         rule: Form paint
  6617.         mask: Form black.!
  6618. isSelectable
  6619.  
  6620.     ^true!
  6621. locationPoints
  6622.  
  6623.     ^Array with: location! !
  6624.  
  6625. !ArrowHeadGlyph methodsFor: 'private'!
  6626. form
  6627.     "Answer the arrowhead form for my vector."
  6628.  
  6629.     | slope absSlope angle |
  6630.     (vector x = 0) ifTrue:
  6631.         [(vector y >= 0)
  6632.             ifTrue: [^FormTable at: 270]
  6633.             ifFalse: [^FormTable at: 90]].
  6634.  
  6635.     slope _ vector y negated asFloat / vector x asFloat.
  6636.     absSlope _ slope abs.
  6637.     (absSlope < 0.5) ifTrue: [angle _ 0].
  6638.     ((absSlope >= 0.5) & (absSlope < 2.0)) ifTrue: [angle _ 45].
  6639.     (absSlope >= 2.0) ifTrue: [angle _ 90].
  6640.     (slope > 0)
  6641.         ifTrue:
  6642.             [(vector x > 0)
  6643.                 ifTrue: [^FormTable at: 0 + angle]
  6644.                 ifFalse: [^FormTable at: 180 + angle]]
  6645.         ifFalse:
  6646.             [(vector x < 0)
  6647.                 ifTrue: [^FormTable at: 180 - angle]
  6648.                 ifFalse: [^FormTable at: 360 - angle]].! !
  6649.  
  6650. !NoteBarGlyph methodsFor: 'initialize-release'!
  6651. initialize
  6652.  
  6653.     super initialize.
  6654.     left _ FreeVariable new.
  6655.     right _ FreeVariable new.
  6656.     top _ FreeVariable new.
  6657.     bottom _ FreeVariable new.
  6658.     width _ FreeVariable new value: 60.
  6659.     height _ FreeVariable value: 3.
  6660.  
  6661.     "The following constraint behaves as follows:
  6662.         1. change p1 -> change p2 or offset
  6663.         2. change p2 -> change offset
  6664.         3. change offset -> change p2"
  6665.     (OffsetC == nil) ifTrue:
  6666.         [OffsetC _ Constraint
  6667.             names: #(p1 p2 offset)
  6668.             methods: #(
  6669.                 'p2 _ p1 + offset'
  6670.                 'offset _ p2 - p1')].
  6671.     (AddC == nil) ifTrue:
  6672.         [AddC _ Constraint
  6673.             names: #(a b sum)
  6674.             methods: #(
  6675.                 'sum _ a + b'
  6676.                 'a _ sum - b'
  6677.                 'b _ sum - a')].
  6678.  
  6679.     width weakDefaultStay.
  6680.     (OffsetC copy) var: (left) var: (right) var: (width) strength: #required.
  6681.     "this is a cheat to save one constraint; 'bottom' is not maintained"
  6682.     "(AddC copy) var: (top) var: (height) var: (bottom) strength: #required."!
  6683. release
  6684.  
  6685.     left release.
  6686.     right release.
  6687.     top release.
  6688.     bottom release.
  6689.     width release.
  6690.     height release.
  6691.     left _ nil.
  6692.     right _ nil.
  6693.     top _ nil.
  6694.     bottom _ nil.
  6695.     width _ nil.
  6696.     height _ nil.! !
  6697.  
  6698. !NoteBarGlyph methodsFor: 'accessing'!
  6699. bottom
  6700.  
  6701.     ^bottom value!
  6702. bottom: aNumber
  6703.  
  6704.     bottom setValue: aNumber.!
  6705. bottomVar
  6706.  
  6707.     ^bottom!
  6708. height
  6709.  
  6710.     ^height value!
  6711. height: aNumber
  6712.  
  6713.     height setValue: aNumber.!
  6714. heightVar
  6715.  
  6716.     ^height!
  6717. left
  6718.  
  6719.     ^left value!
  6720. left: aNumber
  6721.  
  6722.     left setValue: aNumber.!
  6723. leftVar
  6724.  
  6725.     ^left!
  6726. right
  6727.  
  6728.     ^right value!
  6729. right: aNumber
  6730.  
  6731.     right setValue: aNumber.!
  6732. rightVar
  6733.  
  6734.     ^right!
  6735. top
  6736.  
  6737.     ^top value!
  6738. top: aNumber
  6739.  
  6740.     top setValue: aNumber.!
  6741. topVar
  6742.  
  6743.     ^top!
  6744. width
  6745.  
  6746.     ^width value!
  6747. width: aNumber
  6748.  
  6749.     width setValue: aNumber.!
  6750. widthVar
  6751.  
  6752.     ^width! !
  6753.  
  6754. !NoteBarGlyph methodsFor: 'glyph protocol'!
  6755. boundingBox
  6756.  
  6757.     ^((left value - 1)@(top value - 1)) extent:
  6758.         ((width value + 2)@(height value + 2))!
  6759. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6760.  
  6761.     | bar |
  6762.     bar _ (left value@top value) extent: (width value@height value).
  6763.     ("selected value" false)
  6764.         ifTrue:
  6765.             [self
  6766.                 fill: bar
  6767.                 mask: (Form black)
  6768.                 on: aDisplayMedium
  6769.                 at: aDisplayPoint
  6770.                 clip: clipBox]
  6771.         ifFalse:
  6772.             [aDisplayMedium
  6773.                 border: (bar moveBy: aDisplayPoint)
  6774.                 widthRectangle: (1@1 corner: 1@1)
  6775.                 mask: (Form black)
  6776.                 clippingBox: clipBox].
  6777.     "(Forms at: modifier value)
  6778.         displayOn: aDisplayMedium
  6779.         at: (aDisplayPoint + (left value@(top value - 10)))
  6780.         clippingBox: clipBox
  6781.         rule: (Form paint)
  6782.         mask: (Form black).
  6783.     self
  6784.         vLineFrom: ((cutoffX value)@(top value - 1)) length: (height value + 2)
  6785.         on: aDisplayMedium at: aDisplayPoint clip: clipBox."!
  6786. isSelectable
  6787.  
  6788.     ^true!
  6789. locationPoints
  6790.  
  6791.     ^Array with: (left@top)! !
  6792.  
  6793. !NoteBarGlyph methodsFor: 'mouse'!
  6794. handleMouseDown: mousePoint view: view
  6795.     "Change the starting time or duration of a NoteBarGlyph. If multiple NoteBarGlyphs are selected, operate on the entire group."
  6796.  
  6797.     | mode |
  6798.     mode _ (((mousePoint x - left value) < 10) & (Sensor leftShiftDown not))
  6799.         ifTrue: [#changeTime]
  6800.         ifFalse: [#changeDur].
  6801.     MouseConstraints _ OrderedCollection new.
  6802.     MouseConstraints add: (self mouseConstraintFor: mode).
  6803.     view model selected do:
  6804.         [: g |
  6805.          ((g class = self class) and: [g ~~ self]) ifTrue:
  6806.             [MouseConstraints add: (g mouseConstraintFor: mode)]].
  6807.     CurrentPlan _ Planner extractPlanFromInputConstraints: MouseConstraints.
  6808.     view computeBackground.!
  6809. handleMouseMove: mousePoint view: view
  6810.  
  6811.     (MouseConstraints notNil) ifTrue:
  6812.         [CurrentPlan execute.
  6813.          view displayFeedback].!
  6814. handleMouseUp: mousePoint view: view
  6815.     "Clean up the edit constraint and plan."
  6816.  
  6817.     (MouseConstraints notNil) ifTrue:
  6818.         [MouseConstraints do: [: c | c destroyConstraint].
  6819.          MouseConstraints _ nil.
  6820.          CurrentPlan release.
  6821.          CurrentPlan _ nil].!
  6822. mouseConstraintFor: mode
  6823.  
  6824.     (mode == #changeTime)
  6825.         ifTrue: [^XMouseConstraint        "move entire bar left and right"
  6826.                     var: left strength: #preferred
  6827.                     offset: (left value - Sensor cursorPoint x)]
  6828.         ifFalse: [^XMouseConstraint        "change width"
  6829.                     var: right strength: #preferred
  6830.                     offset: (right value - Sensor cursorPoint x)].!
  6831. wantsMouse
  6832.  
  6833.     ^true! !
  6834.  
  6835. !CircleGlyph methodsFor: 'initialize-release'!
  6836. initialize
  6837.  
  6838.     center _ InvisiblePointGlyph new moveTo: 60@60.
  6839.     radius _ FreeVariable value: 15.! !
  6840.  
  6841. !CircleGlyph methodsFor: 'accessing'!
  6842. center
  6843.  
  6844.     ^center!
  6845. radius
  6846.  
  6847.     ^radius value!
  6848. radius: aNumber
  6849.  
  6850.     radius setValue: aNumber.!
  6851. radiusVar
  6852.  
  6853.     ^radius! !
  6854.  
  6855. !CircleGlyph methodsFor: 'glyph protocol'!
  6856. boundingBox
  6857.  
  6858.     | r |
  6859.     r _ radius value rounded.
  6860.     ^(center rounded - (r@r)) extent: ((2*r)@(2*r))!
  6861. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  6862.     "Draw myself. The default is to do nothing. Visible glyphs supply a more specialized behavior for this method."
  6863.  
  6864.     ((Circle new)
  6865.         center: center rounded;
  6866.         form: ((Form extent: 1@1) black);
  6867.         radius: radius value rounded)
  6868.             displayOn: aDisplayMedium
  6869.             at: aDisplayPoint
  6870.             clippingBox: clipBox
  6871.             rule: (Form over)
  6872.             mask: (Form black).!
  6873. isSelectable
  6874.  
  6875.     ^true!
  6876. locationPoints
  6877.  
  6878.     ^Array with: center! !
  6879.  
  6880. !CircleGlyph methodsFor: 'mouse'!
  6881. handleMouseDown: mousePoint view: aView
  6882.     "The message is sent repeatedly while the mouse button is pressed. mousePoint is in local coordinates. The default behavior is to do nothing."
  6883.  
  6884.     changingSize _ ((mousePoint - center) r - radius value) abs < 5.
  6885.     changingSize ifFalse:
  6886.         [aView controller
  6887.             while: [Sensor anyButtonPressed]
  6888.             move: (Array with: center)
  6889.             refPoint: Sensor cursorPoint
  6890.             mergeWith: self]!
  6891. handleMouseMove: mousePoint view: aView
  6892.     "The message is sent repeatedly while the mouse button is pressed. mousePoint is in local coordinates. The default behavior is to do nothing."
  6893.  
  6894.     (changingSize) ifTrue:
  6895.         [self radius: ((mousePoint - center) r max: 1).
  6896.          aView displayScene].!
  6897. wantsMouse
  6898.  
  6899.     ^true! !
  6900.  
  6901. !ParaLinesGlyph methodsFor: 'all'!
  6902. initialize
  6903.  
  6904.     l1 _ LineGlyph new.
  6905.     l2 _ LineGlyph new.
  6906.     (DirectionC isNil) ifTrue:
  6907.         [DirectionC _ Constraint
  6908.             names: #(l1p1 l2p1 l1p2 l2p2)
  6909.             methods: #(
  6910.                 'l1p1 _ l1p2 + (l2p1 - l2p2)'
  6911.                 'l2p1 _ l2p2 + (l1p1 - l1p2)')].
  6912.     (DirectionC copy)
  6913.         var: (l1 p1 xVar) var: (l2 p1 xVar)
  6914.         var: (l1 p2 xVar) var: (l2 p2 xVar) strength: #default.
  6915.     (DirectionC copy)
  6916.         var: (l1 p1 yVar) var: (l2 p1 yVar)
  6917.         var: (l1 p2 yVar) var: (l2 p2 yVar) strength: #default.
  6918.     (DirectionC copy)
  6919.         var: (l1 p2 xVar) var: (l2 p2 xVar)
  6920.         var: (l1 p1 xVar) var: (l2 p1 xVar) strength: #default.
  6921.     (DirectionC copy)
  6922.         var: (l1 p2 yVar) var: (l2 p2 yVar)
  6923.         var: (l1 p1 yVar) var: (l2 p1 yVar) strength: #default.!
  6924. l1
  6925.  
  6926.     ^l1!
  6927. l2
  6928.  
  6929.     ^l2!
  6930. locationPoints
  6931.  
  6932.     ^l1 locationPoints, l2 locationPoints! !
  6933.  
  6934. AttachableMenuGlyph comment:
  6935. 'I can be used to attach a menu to any real glyph. When the SceneController is in ''run'' mode, the menu will be invoked when the mouse is pressed inside my host''s bounding box. The menu consists of a collection of operation names (stored in ''selectors'') and an associated set of scripts (''scripts''). A script is just a sequence of expressions, like a Smalltalk method except that it cannot have local variables. Scripts are compiled into blocks that are invoked when their selector is selected from the menu. The blocks are kept in the variable ''compiledScripts'''!
  6936.  
  6937. !AttachableMenuGlyph methodsFor: 'initialize-release'!
  6938. forHost: aGlyph
  6939.  
  6940.     super initialize.
  6941.     host _ aGlyph.
  6942.     selectors _ OrderedCollection new.
  6943.     scripts _ OrderedCollection new.
  6944.     compiledScripts _ OrderedCollection new.! !
  6945.  
  6946. !AttachableMenuGlyph methodsFor: 'accessing'!
  6947. host
  6948.  
  6949.     ^host! !
  6950.  
  6951. !AttachableMenuGlyph methodsFor: 'glyph protocol'!
  6952. boundingBox
  6953.  
  6954.     ^host boundingBox!
  6955. locationPoints
  6956.  
  6957.     self error: 'Only my host should be moved'! !
  6958.  
  6959. !AttachableMenuGlyph methodsFor: 'enumeration'!
  6960. includesObjectIn: objectList
  6961.     "Answer true if either I or my host is in the given list."
  6962.  
  6963.     ^(objectList includes: host) or:
  6964.       [objectList includes: self]!
  6965. inputGlyphsDo: aBlock
  6966.     "I am an input glyph."
  6967.  
  6968.     aBlock value: self.!
  6969. selectableGlyphsDo: aBlock
  6970.     "I have none."!
  6971. varsDo: aBlock
  6972.     "I have none."!
  6973. visibleGlyphsDo: aBlock
  6974.     "I have none."! !
  6975.  
  6976. !AttachableMenuGlyph methodsFor: 'mouse'!
  6977. handleMouseDown: mousePoint view: view
  6978.     "Invoke or (if the shift key is pressed) edit my menu."
  6979.  
  6980.     (Sensor leftShiftDown)
  6981.         ifTrue: [self editMenu: view]
  6982.         ifFalse: [self invokeMenu: view].!
  6983. wantsMouse
  6984.  
  6985.     ^true! !
  6986.  
  6987. !AttachableMenuGlyph methodsFor: 'script'!
  6988. compile: aString
  6989.     "Answer the evaluation of the given code string (which is usually a block). The code is evaluated in the context of my host, so it may access the host's instance variables."
  6990.  
  6991.     ^Compiler
  6992.         evaluate: aString
  6993.         for: host
  6994.         logged: false!
  6995. editScript: oldScript
  6996.     "Edit the given script string and answer the new script."
  6997.  
  6998.     ^FillInTheBlank
  6999.         request:
  7000. 'Edit the script for this glyph. You many use the pseudovariables
  7001. ''model'' and ''view,'' as well as instance variables of this glyph.'
  7002.         initialAnswer: oldScript! !
  7003.  
  7004. !AttachableMenuGlyph methodsFor: 'menu'!
  7005. addMenuEntry: newSelector script: newScript
  7006.     "Append the given selector and its script to my menu."
  7007.  
  7008.     | newCompiledScript |
  7009.     newCompiledScript _
  7010.         self compile: ('[: model : view | ', newScript, ']').
  7011.     selectors addLast: newSelector.
  7012.     scripts addLast: newScript.
  7013.     compiledScripts addLast: newCompiledScript.!
  7014. addMenuEntryButNot: existingSelectors view: view
  7015.     "Prompt the user for the selector name and the new script. Disallow selectors from the given set. The script may reference the variables 'model' and 'view' as well as the host glyph's instance variables."
  7016.  
  7017.     | newSelector newScript |
  7018.     newSelector _ FillInTheBlank
  7019.         request: 'Type the selector for the new menu item:'.
  7020.     (newSelector = '') ifTrue: [^self].
  7021.     (existingSelectors includes: newSelector) ifTrue:
  7022.         [view flash. ^self].
  7023.     newScript _ self editScript: ''.
  7024.     self addMenuEntry: newSelector script: newScript.!
  7025. editMenu: view
  7026.     "Edit my menu The view is provided to allow feedback by flashing the view. The script for a menu item may reference the variables 'model' and 'view' as well as the host glyph's instance variables."
  7027.  
  7028.     | sel newEntry index newScript newCompiledScript |
  7029.     sel _ (PopUpMenu labelList: (Array
  7030.             with: (Array with: ' add item ' with: ' remove item ')
  7031.             with: selectors)) startUp.
  7032.  
  7033.     (self = 0) ifTrue: [^self].        "user aborted"
  7034.  
  7035.     (sel = 1) ifTrue:    "add a new menu entry"
  7036.         [self addMenuEntryButNot: selectors view: view].
  7037.  
  7038.     (sel = 2) ifTrue:    "remove an existing menu entry"
  7039.         [index _ (PopUpMenu labelList: (Array with: selectors)) startUp.
  7040.          (index = 0) ifTrue: [^self].    "user aborted"
  7041.          selectors removeAtIndex: index.
  7042.          scripts removeAtIndex: index.
  7043.          compiledScripts removeAtIndex: index].
  7044.  
  7045.     (sel > 2) ifTrue:    "edit an existing menu entry"
  7046.         [index _ sel - 2.    "index of entry to edit"
  7047.          newScript _ self editScript: (scripts at: index).
  7048.          (newScript ~= (scripts at: index)) ifTrue:
  7049.              [newCompiledScript _
  7050.                 self compile: ('[: model : view | ', newScript, ']').
  7051.              scripts at: index put: newScript.
  7052.              compiledScripts at: index put: newCompiledScript]].!
  7053. invokeMenu: view
  7054.     "Invoke my menu."
  7055.  
  7056.     | menu block |
  7057.     (selectors isEmpty) ifTrue: [^self].
  7058.     menu _ CustomMenu new.
  7059.     selectors with: compiledScripts do:
  7060.         [: selector : script |
  7061.          menu add: (' ', selector, ' ') action: script].
  7062.     block _ menu invoke.
  7063.     (block isNil) ifFalse:
  7064.         [block value: view model value: view.
  7065.          view displayScene].! !
  7066.  
  7067. ScriptGlyph comment:
  7068. 'I am an abstract class that defines the protocol used by Glyphs that have executable scripts.'!
  7069.  
  7070. !ScriptGlyph methodsFor: 'initialize-release'!
  7071. initialize
  7072.  
  7073.     super initialize.
  7074.     script _ ''.
  7075.     compiledScript _ nil! !
  7076.  
  7077. !ScriptGlyph methodsFor: 'script'!
  7078. editScript
  7079.     "Edit my script. The script may reference the variables 'model,' 'view,' and 'val,' as well as this glyph's instance variables."
  7080.  
  7081.     | newScript |
  7082.     newScript _ FillInTheBlank
  7083.         request:
  7084. 'Edit the script for this glyph. You many use the pseudovariables
  7085. ''model,'' ''view,'' and ''val,'' as well as instance variables of this glyph.'
  7086.         initialAnswer: script.
  7087.  
  7088.     (newScript ~= script) ifTrue:
  7089.         [self script: newScript].!
  7090. script
  7091.     "Answer my script."
  7092.  
  7093.     ^script!
  7094. script: scriptString
  7095.     "Compile and store the given script. The script may reference the variables 'model,' 'view,' and 'val,' as well as this glyph's instance variables."
  7096.  
  7097.     script _ scriptString.
  7098.     (script isEmpty)
  7099.         ifTrue: [compiledScript _ nil]
  7100.         ifFalse:
  7101.             [compiledScript _ self compile:
  7102.                 ('[: model : view : val | ', script, ']')].! !
  7103.  
  7104. !HSliderGlyph methodsFor: 'initialize-release'!
  7105. initialize
  7106.  
  7107.     super initialize.
  7108.     box _ (RectangleGlyph new) width: 128; height: 11.
  7109.     minVal _ FreeVariable value: 0.0.
  7110.     maxVal _ FreeVariable value: 127.0.
  7111.     majorTicks _ FreeVariable value: 3.
  7112.     minorTicks _ FreeVariable value: 11.
  7113.     value _ FreeVariable value: 0.! !
  7114.  
  7115. !HSliderGlyph methodsFor: 'accessing'!
  7116. box
  7117.  
  7118.     ^box!
  7119. height: aNumber
  7120.  
  7121.     box height: aNumber.!
  7122. majorTicks
  7123.  
  7124.     ^majorTicks value!
  7125. majorTicks: aNumber
  7126.  
  7127.     majorTicks setValue: aNumber.!
  7128. majorTicksVar
  7129.  
  7130.     ^majorTicks!
  7131. maxVal
  7132.  
  7133.     ^maxVal value!
  7134. maxVal: aNumber
  7135.  
  7136.     maxVal setValue: aNumber.!
  7137. maxValVar
  7138.  
  7139.     ^maxVal!
  7140. minorTicks
  7141.  
  7142.     ^minorTicks value!
  7143. minorTicks: aNumber
  7144.  
  7145.     minorTicks setValue: aNumber.!
  7146. minorTicksVar
  7147.  
  7148.     ^minorTicks!
  7149. minVal
  7150.  
  7151.     ^minVal value!
  7152. minVal: aNumber
  7153.  
  7154.     minVal setValue: aNumber.!
  7155. minValVar
  7156.  
  7157.     ^minVal!
  7158. value
  7159.  
  7160.     ^value value!
  7161. value: aNumber
  7162.  
  7163.     value setValue: ((aNumber max: minVal value) min: maxVal value).!
  7164. valueVar
  7165.  
  7166.     ^value!
  7167. width: aNumber
  7168.  
  7169.     box width: aNumber.! !
  7170.  
  7171. !HSliderGlyph methodsFor: 'glyph protocol'!
  7172. boundingBox
  7173.  
  7174.     ^((box left - 3)@(box top - 1)) extent:
  7175.         (box width + 7)@((box height + 2) max: ((box height // 2) + 8))!
  7176. displayAxisOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  7177.  
  7178.     | myHeight myWidth origin |
  7179.     myHeight _ box height.
  7180.     myWidth _ box width.
  7181.     origin _ box left@box top.
  7182.     self
  7183.         hLineFrom: (origin + (0@(myHeight // 2))) length: myWidth
  7184.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  7185.     self
  7186.         vLineFrom: origin length: (myHeight - 1)
  7187.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  7188.     self
  7189.         vLineFrom: (origin + (myWidth@0)) length: (myHeight - 1)
  7190.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.!
  7191. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  7192.  
  7193.     | myHeight markForm scaleFactor markX |
  7194.     myHeight _ box height.
  7195.     self displayAxisOn: aDisplayMedium at: aDisplayPoint clip: clipBox.
  7196.     self
  7197.         displayTicks: majorTicks value
  7198.         size: (myHeight // 2)
  7199.         on: aDisplayMedium
  7200.         at: aDisplayPoint
  7201.         clip: clipBox.
  7202.     self
  7203.         displayTicks: minorTicks value
  7204.         size: (myHeight // 3)
  7205.         on: aDisplayMedium
  7206.         at: aDisplayPoint
  7207.         clip: clipBox.
  7208.     markForm _ (Form
  7209.             extent: 7@6
  7210.             fromArray: #(4096 14336 31744 65024 65024 65024)
  7211.             offset: -3@1).
  7212.     scaleFactor _ box width asFloat / (maxVal value - minVal value) asFloat.
  7213.     markX _ (scaleFactor * (value value asFloat - minVal value asFloat)) rounded.
  7214.     markX _ (markX min: box width) max: 0.    "keep marker in range [0..width]"
  7215.     markForm
  7216.         displayOn: aDisplayMedium
  7217.         at: (aDisplayPoint + (box left@box top) + (markX@(myHeight // 2)))
  7218.         clippingBox: clipBox
  7219.         rule: (Form paint)
  7220.         mask: (Form black).!
  7221. displayTicks: tickCount size: tickSize on: aDisplayMedium at: aDisplayPoint clip: clipBox
  7222.  
  7223.     | tickHeight tickTop tickSeparation tickX i |
  7224.     tickHeight _ tickSize min: (box height // 2).
  7225.     tickTop _ box top + (box height // 2) - tickHeight.
  7226.     tickSeparation _ box width asFloat / (tickCount + 1).
  7227.     tickX _ box left asFloat + tickSeparation.
  7228.     i _ tickCount.
  7229.     [i > 0] whileTrue:
  7230.         [self
  7231.             vLineFrom: ((tickX rounded)@tickTop) length: tickHeight
  7232.             on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  7233.          tickX _ tickX + tickSeparation.
  7234.          i _ i - 1].!
  7235. isSelectable
  7236.  
  7237.     ^true!
  7238. locationPoints
  7239.  
  7240.     ^Array with: box center! !
  7241.  
  7242. !HSliderGlyph methodsFor: 'enumeration'!
  7243. selectableGlyphsDo: aBlock
  7244.     "None of my subparts is selectable."
  7245.  
  7246.     aBlock value: self.!
  7247. visibleGlyphsDo: aBlock
  7248.     "None of my subparts is visible."
  7249.  
  7250.     aBlock value: self.! !
  7251.  
  7252. !HSliderGlyph methodsFor: 'mouse'!
  7253. handleMouseDown: mousePoint view: view
  7254.  
  7255.     (Sensor leftShiftDown)
  7256.         ifTrue: [^self editScript]
  7257.         ifFalse:
  7258.             [editConstraint _ EditConstraint var: value strength: #preferred.
  7259.              (editConstraint isSatisfied)
  7260.                 ifTrue:
  7261.                     [plan _ Planner extractPlanFromInputConstraints: (Array with: editConstraint).
  7262.                      view computeBackground]
  7263.                 ifFalse: [view flash]].!
  7264. handleMouseMove: mousePoint view: view
  7265.     "Move the slider, show feedback, and run the script. If the shift key is pressed, the user wants to edit the script, so do nothing."
  7266.  
  7267.     | scaleFactor relativeX lastX scaledValue |
  7268.     scaleFactor _ (maxVal value - minVal value) asFloat / box width asFloat.
  7269.     relativeX _ mousePoint x - box left.
  7270.     relativeX _ relativeX max: 0.
  7271.     relativeX _ relativeX min: box width.
  7272.     ((relativeX ~~ lastX) and:
  7273.      [(editConstraint notNil) and: [editConstraint isSatisfied]]) ifTrue:
  7274.         [scaledValue _ minVal value asFloat + (scaleFactor * relativeX asFloat).
  7275.          value value: scaledValue.
  7276.          plan execute.
  7277.          view displayFeedback.
  7278.          (compiledScript notNil) ifTrue:
  7279.             [compiledScript value: view model value: view value: scaledValue].
  7280.          lastX _ relativeX].!
  7281. handleMouseUp: mousePoint view: view
  7282.     "Clean up the edit constraint and plan."
  7283.  
  7284.     (editConstraint notNil) ifTrue:
  7285.         [editConstraint destroyConstraint.
  7286.          editConstraint _ nil.
  7287.          plan release.
  7288.          plan _ nil].!
  7289. wantsMouse
  7290.  
  7291.     ^true! !
  7292.  
  7293. !HAtomicSliderGlyph methodsFor: 'mouse'!
  7294. handleMouseMove: mousePoint view: view
  7295.     "Move the slider, show feedback, and run the script. If the shift key is pressed, the user wants to edit the script, so do nothing."
  7296.  
  7297.     | scaleFactor relativeX lastX scaledValue |
  7298.     scaleFactor _ (maxVal value - minVal value) asFloat / box width asFloat.
  7299.     relativeX _ mousePoint x - box left.
  7300.     relativeX _ relativeX max: 0.
  7301.     relativeX _ relativeX min: box width.
  7302.     ((relativeX ~~ lastX) and:
  7303.      [(editConstraint notNil) and: [editConstraint isSatisfied]]) ifTrue:
  7304.         [scaledValue _ minVal value asFloat + (scaleFactor * relativeX asFloat).
  7305.          value value: scaledValue.
  7306.          plan execute.
  7307.          view displayFeedback.
  7308.          lastX _ relativeX].!
  7309. handleMouseUp: mousePoint view: view
  7310.     "Clean up the edit constraint and plan."
  7311.  
  7312.     (editConstraint notNil) ifTrue:
  7313.         [editConstraint destroyConstraint.
  7314.          editConstraint _ nil.
  7315.          plan release.
  7316.          plan _ nil].
  7317.     (compiledScript notNil) ifTrue:
  7318.         [compiledScript value: view model value: view value: value value].! !
  7319.  
  7320. !ThermometerGlyph methodsFor: 'initialize-release'!
  7321. initialize
  7322.     super initialize.
  7323.     editBox _ (RectangleGlyph new) width: 20; height: 200.
  7324.     minVal _ FreeVariable value: -100.0.
  7325.     underVal _ FreeVariable value: -120.0.
  7326.     maxVal _ FreeVariable value: 300.0.
  7327.     overVal _ FreeVariable value: 320.0.
  7328.     temperature _ FreeVariable value: 0.
  7329.     over _ FreeVariable value: false.
  7330.     under _ FreeVariable value: false.
  7331.     mercury _ PointGlyph new initialize.
  7332.     mercury moveTo: editBox center asPoint + editBox width asPoint.
  7333.     textGlyph _ TextGlyph new initialize.
  7334.     PrintConstraint isNil ifTrue: [PrintConstraint _ Constraint names: #(text temp ) methods: #('text _ temp printString' 'temp _ text asNumber' )].
  7335.     PrintConstraint copy
  7336.         var: textGlyph textVar
  7337.         var: temperature
  7338.         strength: #required.
  7339.     EqualityConstraint
  7340.         var: mercury yVar
  7341.         var: textGlyph box bottomVar
  7342.         strength: #required.
  7343.     "EqualityConstraint  
  7344.     var: mercury xVar  
  7345.     var: textGlyph box leftVar  
  7346.     strength: #required."
  7347.     EqualityConstraint
  7348.         var: editBox rightVar
  7349.         var: textGlyph box leftVar
  7350.         strength: #required.
  7351.     MercConstraint isNil ifTrue: [MercConstraint _ Constraint names: #(boxh boxt merc min max temp ) methods: #('merc _ ThermometerGlyph internalMsg1: min and: max and: temp and: boxh and: boxt' )].
  7352.     MercConstraint copy
  7353.         var: editBox heightVar
  7354.         var: editBox topVar
  7355.         var: mercury yVar
  7356.         var: minVal
  7357.         var: maxVal
  7358.         var: temperature
  7359.         strength: #required.
  7360.     OverConstraint isNil ifTrue: [OverConstraint _ Constraint names: #(temp over overval ) methods: #('over _ ThermometerGlyph internalMsg2: temp and: overval' )].
  7361.     OverConstraint copy
  7362.         var: temperature
  7363.         var: over
  7364.         var: overVal
  7365.         strength: #required.
  7366.     UnderConstraint isNil ifTrue: [UnderConstraint _ Constraint names: #(temp under underval ) methods: #('under _ ThermometerGlyph internalMsg3: temp and: underval' )].
  7367.     UnderConstraint copy
  7368.         var: temperature
  7369.         var: under
  7370.         var: underVal
  7371.         strength: #required! !
  7372.  
  7373. !ThermometerGlyph methodsFor: 'accessing'!
  7374. editBox
  7375.     ^editBox!
  7376. maxVal: aNumber 
  7377.     maxVal setValue: aNumber!
  7378. minVal: aNumber 
  7379.     minVal setValue: aNumber!
  7380. overVal: n underVal: m 
  7381.     overVal value: n.
  7382.     underVal value: m!
  7383. temperature
  7384.  
  7385.     ^temperature value!
  7386. temperature: aNumber
  7387.  
  7388.     temperature setValue: ((aNumber max: minVal value) min: maxVal value).!
  7389. temperatureVar
  7390.     ^temperature! !
  7391.  
  7392. !ThermometerGlyph methodsFor: 'glyph protocol'!
  7393. boundingBox
  7394.     | r left right top bottom bf |
  7395.     false ifTrue: [self stilltodo].
  7396.     bf _ under value
  7397.                 ifTrue: [BulbForm2]
  7398.                 ifFalse: [BulbForm].
  7399.     r _ editBox asRectangle.
  7400.     left _ r left - (bf width - r width // 2).
  7401.     right _ r right + (bf width - r width // 2).
  7402.     top _ r top.
  7403.     over value ifTrue: [top _ top - CapForm height].
  7404.     bottom _ r bottom + bf height.
  7405.     ^left @ top corner: right @ bottom!
  7406. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  7407.     | markY box |
  7408.     box _ editBox asRectangle moveBy: aDisplayPoint.
  7409.     markY _ (editBox left @ mercury y) corner: editBox bottomRight.
  7410.     aDisplayMedium fill: editBox mask: Form white.
  7411.     aDisplayMedium fill: markY mask: Form gray.
  7412.     aDisplayMedium border: editBox asRectangle width: 1.
  7413.     under value
  7414.         ifTrue: [BulbForm2 displayOn: aDisplayMedium at: editBox bottomLeft - (0 @ 1) - (BulbForm2 width - editBox width // 2 @ 0)]
  7415.         ifFalse: [BulbForm displayOn: aDisplayMedium at: editBox bottomLeft - (0 @ 1) - (BulbForm width - editBox width // 2 @ 0)].
  7416.     over value ifTrue: [CapForm displayOn: aDisplayMedium at: editBox topLeft - (((CapForm width - editBox width // 2)) @ (CapForm height - 1))].
  7417.     false ifTrue: [self stilltodo]!
  7418. isSelectable
  7419.     ^true!
  7420. locationPoints
  7421.     ^Array with: editBox center!
  7422. old.displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  7423.     | scaleFactor markY over1 under1 |
  7424.     "textGlyph displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox."
  7425.     scaleFactor _ editBox height asFloat / (maxVal value - minVal value) asFloat.
  7426.     markY _ (scaleFactor * (temperature value asFloat - minVal value asFloat)) rounded.
  7427.     over1 _ markY > (editBox height + 40).
  7428.     under1 _ markY < -60.
  7429.     markY _ (markY max: 0)
  7430.                 min: editBox height.
  7431.     markY _ editBox height - markY.
  7432.     markY _ editBox topLeft + (0 @ markY) corner: editBox bottomRight.
  7433.     aDisplayMedium fill: editBox mask: Form white.
  7434.     aDisplayMedium fill: markY mask: Form gray.
  7435.     aDisplayMedium border: editBox asRectangle width: 1.
  7436.     under1
  7437.         ifTrue: [BulbForm2 displayOn: aDisplayMedium at: editBox bottomLeft - (0 @ 1) - (BulbForm2 width - editBox width // 2 @ 0)]
  7438.         ifFalse: [BulbForm displayOn: aDisplayMedium at: editBox bottomLeft - (0 @ 1) - (BulbForm width - editBox width // 2 @ 0)].
  7439.     over1 ifTrue: [CapForm displayOn: aDisplayMedium at: editBox topLeft - (0 @ (CapForm height - 1))].
  7440.     false ifTrue: [self stilltodo]! !
  7441.  
  7442. !ThermometerGlyph methodsFor: 'enumeration'!
  7443. selectableGlyphsDo: aBlock 
  7444.     aBlock value: self.
  7445.     "aBlock value: mercury."
  7446.     aBlock value: textGlyph!
  7447. visibleGlyphsDo: aBlock
  7448.     aBlock value: self.
  7449.     "aBlock value: mercury."
  7450.     aBlock value: textGlyph! !
  7451.  
  7452. !ThermometerGlyph methodsFor: 'mouse'!
  7453. handleMouseDown: mousePoint view: view 
  7454.     Sensor leftShiftDown
  7455.         ifTrue: [^self editScript]
  7456.         ifFalse: 
  7457.             [editConstraint _ EditConstraint var: temperature strength: #preferred.
  7458.             editConstraint2 _ EditConstraint var: mercury yVar strength: #preferred.
  7459.             editConstraint isSatisfied
  7460.                 ifTrue: 
  7461.                     [plan _ Planner extractPlanFromInputConstraints: (Array with: editConstraint with: editConstraint2).
  7462.                     view computeBackground]
  7463.                 ifFalse: [view flash]]!
  7464. handleMouseMove: mousePoint view: view 
  7465.     "Move the slider, show feedback, and run the script. If the shift key is pressed, 
  7466.     the user wants to edit the script, so do nothing."
  7467.  
  7468.     | scaleFactor relativeY scaledValue |
  7469.     scaleFactor _ (maxVal value - minVal value) asFloat / editBox height asFloat.
  7470.     relativeY _ mousePoint y - editBox top.
  7471.     relativeY _ relativeY max: 0.
  7472.     relativeY _ relativeY min: editBox height.
  7473.     relativeY _ editBox height - relativeY.
  7474.     (relativeY ~~ prevY and: [editConstraint notNil and: [editConstraint isSatisfied]])
  7475.         ifTrue: 
  7476.             [scaledValue _ minVal value asFloat + (scaleFactor * relativeY asFloat).
  7477.             temperature value: scaledValue.
  7478.             mercury yVar value: (editBox height - relativeY)  + (editBox top).
  7479.             plan execute.
  7480.             view displayFeedback.
  7481.             compiledScript notNil ifTrue: [compiledScript
  7482.                     value: view model
  7483.                     value: view
  7484.                     value: scaledValue].
  7485.             prevY _ relativeY]!
  7486. handleMouseUp: mousePoint view: view 
  7487.     "Clean up the edit constraint and plan."
  7488.  
  7489.     editConstraint notNil
  7490.         ifTrue: 
  7491.             [editConstraint destroyConstraint.
  7492.             editConstraint _ nil.
  7493.             editConstraint2 destroyConstraint.
  7494.             editConstraint2 _ nil.
  7495.             plan release.
  7496.             plan _ nil]!
  7497. wantsMouse
  7498.     ^true! !
  7499.  
  7500. !ThreeProngTextGlyph methodsFor: 'initialize-release'!
  7501. initialize
  7502.     "ThreeProngTextGlyph releaseConstraints"
  7503.  
  7504.     super initialize.
  7505.     textGlyph _ TextGlyph new initialize.
  7506.     left _ PointGlyph new initialize.
  7507.     right _ PointGlyph new initialize.
  7508.     down _ PointGlyph new initialize.
  7509.     left moveTo: 10 @ 10.
  7510.     right moveTo: 100 @ 10.
  7511.     down moveTo: 45@ 50.
  7512.     textGlyph moveTo: 40 @ 15.
  7513.     offset _ PointGlyph new initialize.
  7514.     offset moveTo: 0 @ 8.
  7515.     CenterOffsetConstraint isNil ifTrue: [CenterOffsetConstraint _ (Constraint names: #(out left right down off ) methods: #('out _ ((left + right + down) // 3) - off' 'off _ ((left + right + down) // 3) - out' ))
  7516.                     name: 'center offset'].
  7517.     StayConstraint
  7518.         var: offset xVar
  7519.         strength: #default.
  7520.     CenterOffsetConstraint copy
  7521.         var: textGlyph box leftVar
  7522.         var: left xVar
  7523.         var: right xVar
  7524.         var: down xVar
  7525.         var: offset xVar
  7526.         strength: #required.
  7527.     StayConstraint
  7528.         var: offset yVar
  7529.         strength: #default.
  7530.     CenterOffsetConstraint copy
  7531.         var: textGlyph box topVar
  7532.         var: left yVar
  7533.         var: right yVar
  7534.         var: down yVar
  7535.         var: offset yVar
  7536.         strength: #required!
  7537. left: l right: r down: d string: s
  7538.     | stays |  
  7539.     stays _ Set new.
  7540.     stays add: (StayConstraint
  7541.         var: "textGlyph box leftVar" offset xVar
  7542.         strength: #strongPreferred).
  7543.     stays add: (StayConstraint
  7544.         var: "textGlyph box topVar" offset yVar
  7545.         strength: #strongPreferred).
  7546.     stays add: (StayConstraint
  7547.         var: l xVar
  7548.         strength: #strongPreferred).
  7549.     stays add: (StayConstraint
  7550.         var: l yVar
  7551.         strength: #strongPreferred).
  7552.     stays add: (StayConstraint
  7553.         var: r xVar
  7554.         strength: #strongPreferred).
  7555.     stays add: (StayConstraint
  7556.         var: r yVar
  7557.         strength: #strongPreferred).
  7558.     stays add: (StayConstraint
  7559.         var: d xVar
  7560.         strength: #strongPreferred).
  7561.     stays add: (StayConstraint
  7562.         var: d yVar
  7563.         strength: #strongPreferred).
  7564.     EqualityConstraint
  7565.         var: l xVar
  7566.         var: left xVar
  7567.         strength: #required.
  7568.     EqualityConstraint
  7569.         var: l yVar
  7570.         var: left yVar
  7571.         strength: #required.
  7572.     EqualityConstraint
  7573.         var: r xVar
  7574.         var: right xVar
  7575.         strength: #required.
  7576.     EqualityConstraint
  7577.         var: r yVar
  7578.         var: right yVar
  7579.         strength: #required.
  7580.     EqualityConstraint
  7581.         var: d xVar
  7582.         var: down xVar
  7583.         strength: #required.
  7584.     EqualityConstraint
  7585.         var: d yVar
  7586.         var: down yVar
  7587.         strength: #required.
  7588.     stays do: [:each | each destroyConstraint].
  7589.     textGlyph text: s! !
  7590.  
  7591. !ThreeProngTextGlyph methodsFor: 'access'!
  7592. offset: p
  7593.     offset xVar value: p x.
  7594.     offset yVar value: p y! !
  7595.  
  7596. !ThreeProngTextGlyph methodsFor: 'glyph protocol'!
  7597. boundingBox
  7598.     ^textGlyph boundingBox!
  7599. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  7600.     | r |
  7601.     r _ textGlyph box asRectangle moveBy: aDisplayPoint.
  7602.     (Line
  7603.         from: left asPoint
  7604.         to: r left @ r top
  7605.         withForm: (Form extent: 1 @ 1) black)
  7606.         displayOn: aDisplayMedium
  7607.         at: aDisplayPoint.
  7608.     (Line
  7609.         from: right asPoint
  7610.         to: r right @ r center y
  7611.         withForm: (Form extent: 1 @ 1) black)
  7612.         displayOn: aDisplayMedium
  7613.         at: aDisplayPoint.
  7614.     (Line
  7615.         from: down asPoint
  7616.         to: r left @ r bottom
  7617.         withForm: (Form extent: 1 @ 1) black)
  7618.         displayOn: aDisplayMedium
  7619.         at: aDisplayPoint.
  7620.     aDisplayMedium fill: (r insetBy: -1 @ -1) mask: Form white.
  7621.     textGlyph
  7622.         displayOn: aDisplayMedium
  7623.         at: aDisplayPoint
  7624.         clip: clipBox.
  7625.     aDisplayMedium border: (r insetBy: -3 @ -3)
  7626.         width: 2 mask: Form gray.
  7627.     false ifTrue: [self stilltodo]!
  7628. isSelectable
  7629.     ^true!
  7630. locationPoints
  7631.     ^Array
  7632.         with: textGlyph box center"
  7633.         with: left asPoint
  7634.         with: right asPoint
  7635.         with: down asPoint"! !
  7636.  
  7637. !ThreeProngTextGlyph methodsFor: 'enumeration'!
  7638. selectableGlyphsDo: aBlock 
  7639.     aBlock value: self.
  7640.     aBlock value: textGlyph.
  7641. "aBlock value: left.
  7642. aBlock value: right.
  7643. aBlock value: down"!
  7644. visibleGlyphsDo: aBlock 
  7645.     aBlock value: self.
  7646.     aBlock value: textGlyph! !
  7647.  
  7648. !TwoProngTextGlyph methodsFor: 'initialize-release'!
  7649. initialize
  7650.     "TwoProngTextGlyph releaseConstraints"
  7651.  
  7652.     super initialize.
  7653.     textGlyph _ TextGlyph new initialize.
  7654.     left _ PointGlyph new initialize.
  7655.     right _ PointGlyph new initialize.
  7656.     left moveTo: 10 @ 10.
  7657.     right moveTo: 100 @ 10.
  7658.     textGlyph moveTo: 40 @ 15.
  7659.     offset _ PointGlyph new initialize.
  7660.     offset moveTo: 10 @ 40.
  7661.     CenterOffsetConstraint isNil ifTrue: [CenterOffsetConstraint _ (Constraint names: #(out left right off ) methods: #('out _ ((left + right) // 2) - off' 'off _ ((left + right) // 2) - out' ))
  7662.                     name: 'center offset'].
  7663.     StayConstraint
  7664.         var: offset xVar
  7665.         strength: #default.
  7666.     CenterOffsetConstraint copy
  7667.         var: textGlyph box leftVar
  7668.         var: left xVar
  7669.         var: right xVar
  7670.         var: offset xVar
  7671.         strength: #required.
  7672.     StayConstraint
  7673.         var: offset yVar
  7674.         strength: #default.
  7675.     CenterOffsetConstraint copy
  7676.         var: textGlyph box topVar
  7677.         var: left yVar
  7678.         var: right yVar
  7679.         var: offset yVar
  7680.         strength: #required!
  7681. left: l right: r string: s
  7682.     | stays |  
  7683.     stays _ Set new.
  7684.     stays add: (StayConstraint
  7685.         var: textGlyph box leftVar
  7686.         strength: #strongPreferred).
  7687.     stays add: (StayConstraint
  7688.         var: textGlyph box topVar
  7689.         strength: #strongPreferred).
  7690.     EqualityConstraint
  7691.         var: l xVar
  7692.         var: left xVar
  7693.         strength: #required.
  7694.     EqualityConstraint
  7695.         var: l yVar
  7696.         var: left yVar
  7697.         strength: #required.
  7698.     EqualityConstraint
  7699.         var: r xVar
  7700.         var: right xVar
  7701.         strength: #required.
  7702.     EqualityConstraint
  7703.         var: r yVar
  7704.         var: right yVar
  7705.         strength: #required.
  7706.     stays do: [:each | each destroyConstraint].
  7707.     textGlyph text: s! !
  7708.  
  7709. !TwoProngTextGlyph methodsFor: 'accessing'!
  7710. left ^left!
  7711. right ^right!
  7712. text
  7713.     ^textGlyph! !
  7714.  
  7715. !TwoProngTextGlyph methodsFor: 'glyph protocol'!
  7716. boundingBox
  7717.     ^textGlyph boundingBox!
  7718. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  7719.     | r |
  7720.     r _ textGlyph box asRectangle moveBy: aDisplayPoint.
  7721.     (Line
  7722.         from: left asPoint
  7723.         to: r left @ r center y
  7724.         withForm: (Form extent: 1 @ 1) black)
  7725.         displayOn: aDisplayMedium
  7726.         at: aDisplayPoint.
  7727.     (Line
  7728.         from: right asPoint
  7729.         to: r right @ r center y
  7730.         withForm: (Form extent: 1 @ 1) black)
  7731.         displayOn: aDisplayMedium
  7732.         at: aDisplayPoint.
  7733.     aDisplayMedium fill: (r insetBy: -1 @ -1) mask: Form white.
  7734.     textGlyph
  7735.         displayOn: aDisplayMedium
  7736.         at: aDisplayPoint
  7737.         clip: clipBox.
  7738.     aDisplayMedium border: (r insetBy: -3 @ -3)
  7739.         width: 2.
  7740.     false ifTrue: [self stilltodo]!
  7741. isSelectable
  7742.     ^true!
  7743. locationPoints
  7744.     ^Array
  7745.         with: textGlyph box center"
  7746.         with: left asPoint
  7747.         with: right asPoint"! !
  7748.  
  7749. !TwoProngTextGlyph methodsFor: 'enumeration'!
  7750. selectableGlyphsDo: aBlock 
  7751.     aBlock value: self.
  7752.     aBlock value: textGlyph.
  7753. aBlock value: left.
  7754. aBlock value: right!
  7755. visibleGlyphsDo: aBlock 
  7756.     aBlock value: self.
  7757.     aBlock value: textGlyph! !
  7758.  
  7759. !RadioButtonsGlyph methodsFor: 'initialize-release'!
  7760. initialize
  7761.  
  7762.     super initialize.
  7763.     box _ RectangleGlyph new.
  7764.     count _ FreeVariable value: 5.
  7765.     orientation _ FreeVariable value: #horizontal.
  7766.     checkBoxSize _ FreeVariable value: 11.
  7767.     spacing _ FreeVariable value: 15.
  7768.     value _ FreeVariable value: 1.
  7769.     (WidthC == nil) ifTrue:
  7770.         [WidthC _ Constraint
  7771.             names: #(width count orientation boxSize spacing)
  7772.             methods: #(
  7773.                 'width _ (orientation == #horizontal)
  7774.                     ifTrue: [(count * boxSize) + ((count - 1) * spacing)]
  7775.                     ifFalse: [boxSize]')].
  7776.     (HeightC == nil) ifTrue:
  7777.         [HeightC _ Constraint
  7778.             names: #(height count orientation boxSize spacing)
  7779.             methods: #(
  7780.                 'height _ (orientation == #vertical)
  7781.                     ifTrue: [(count * boxSize) + ((count - 1) * spacing)]
  7782.                     ifFalse: [boxSize]')].
  7783.     (WidthC copy)
  7784.         var: (box widthVar) var: (count) var: (orientation)
  7785.         var: (checkBoxSize) var: (spacing) strength: #required.
  7786.     (HeightC copy)
  7787.         var: (box heightVar) var: (count) var: (orientation)
  7788.         var: (checkBoxSize) var: (spacing) strength: #required.! !
  7789.  
  7790. !RadioButtonsGlyph methodsFor: 'accessing'!
  7791. box
  7792.  
  7793.     ^box!
  7794. checkBoxSize
  7795.  
  7796.     ^checkBoxSize value!
  7797. checkBoxSize: aNumber
  7798.     "Set the size of the check boxes to the given number of pixels."
  7799.  
  7800.     checkBoxSize setValue: aNumber rounded.!
  7801. checkBoxSizeVar
  7802.  
  7803.     ^checkBoxSize!
  7804. count
  7805.  
  7806.     ^count value!
  7807. count: aNumber
  7808.     "Set the number of check boxes in this set to the given number."
  7809.  
  7810.     count setValue: aNumber rounded.!
  7811. countVar
  7812.  
  7813.     ^count!
  7814. orientation
  7815.  
  7816.     ^orientation value!
  7817. orientationVar
  7818.  
  7819.     ^orientation!
  7820. setHorizontalOrientation
  7821.  
  7822.     orientation setValue: #horizontal.!
  7823. setVerticalOrientation
  7824.  
  7825.     orientation setValue: #vertical.!
  7826. spacing
  7827.  
  7828.     ^spacing value!
  7829. spacing: aNumber
  7830.     "Set the inter-box distance to the given number of pixels."
  7831.  
  7832.     spacing setValue: aNumber.!
  7833. spacingVar
  7834.  
  7835.     ^spacing!
  7836. value
  7837.  
  7838.     ^value value!
  7839. value: aNumber
  7840.     "Set the index of the selected item (i.e. and integer in the range [1..count])."
  7841.  
  7842.     value setValue: aNumber rounded.!
  7843. valueVar
  7844.  
  7845.     ^value! !
  7846.  
  7847. !RadioButtonsGlyph methodsFor: 'glyph protocol'!
  7848. boundingBox
  7849.  
  7850.     ^(box left - 1@box top - 2) corner: (box right + 1@box bottom + 1)!
  7851. displayBoxOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  7852.  
  7853.     | length |
  7854.     length _ checkBoxSize value rounded - 1.
  7855.     self    hLineFrom: (0@0) length: length
  7856.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  7857.     self    vLineFrom: (0@0) length: length
  7858.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  7859.     self    hLineFrom: (0@length) length: length
  7860.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  7861.     self    vLineFrom: (length@0) length: (length + 1)
  7862.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.!
  7863. displayCheckOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  7864.  
  7865.     | adjustedBoxSize |
  7866.     adjustedBoxSize _ checkBoxSize value rounded - 1.
  7867.     self
  7868.         lineFrom: (0@0) to: (adjustedBoxSize@adjustedBoxSize)
  7869.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.
  7870.     self
  7871.         lineFrom: (0@adjustedBoxSize) to: (adjustedBoxSize@0)
  7872.         on: aDisplayMedium at: aDisplayPoint clip: clipBox.!
  7873. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  7874.  
  7875.     | origin delta boxOrigin |
  7876.     origin _ (aDisplayPoint + (box left@box top)) rounded.
  7877.     delta _ (spacing value + checkBoxSize value) rounded.
  7878.     1 to: count value rounded do:
  7879.         [: i |
  7880.          boxOrigin _ (orientation value == #horizontal)
  7881.             ifTrue: [origin + (((i - 1) * delta)@0)]
  7882.             ifFalse: [origin + (0@((i - 1) * delta))].
  7883.          self displayBoxOn: aDisplayMedium at: boxOrigin clip: clipBox.
  7884.          (i == value value) ifTrue:
  7885.             [self displayCheckOn: aDisplayMedium at: boxOrigin clip: clipBox]].!
  7886. isSelectable
  7887.  
  7888.     ^true!
  7889. locationPoints
  7890.  
  7891.     ^Array with: box center! !
  7892.  
  7893. !RadioButtonsGlyph methodsFor: 'enumeration'!
  7894. selectableGlyphsDo: aBlock
  7895.     "None of my subparts is selectable."
  7896.  
  7897.     aBlock value: self.!
  7898. visibleGlyphsDo: aBlock
  7899.     "None of my subparts is visible."
  7900.  
  7901.     aBlock value: self.! !
  7902.  
  7903. !RadioButtonsGlyph methodsFor: 'mouse'!
  7904. displayIn: view
  7905.     "Show feedback during mouse interaction."
  7906.  
  7907.     | myBox myForm |
  7908.     myBox _ self boundingBox.
  7909.     myForm _ Form extent: myBox extent.
  7910.     self displayOn: myForm at: ((0@0) - myBox topLeft) clip: myForm computeBoundingBox.
  7911.     myForm
  7912.         displayOn: Display
  7913.         at: (view insetDisplayBox topLeft + myBox topLeft + view mouseOffset)
  7914.         clippingBox: (view insetDisplayBox)
  7915.         rule: (Form over)
  7916.         mask: (Form black).!
  7917. handleMouseDown: mousePoint view: view
  7918.  
  7919.     (Sensor leftShiftDown)
  7920.         ifTrue: [^self editScript]
  7921.         ifFalse:
  7922.             [editConstraint _ EditConstraint var: value strength: #preferred.
  7923.              (editConstraint isSatisfied)
  7924.                 ifTrue:
  7925.                     [plan _ Planner extractPlanFromInputConstraints:
  7926.                         (Array with: editConstraint)]
  7927.                 ifFalse: [view flash]].!
  7928. handleMouseMove: mousePoint view: view
  7929.     "Show feedback as the user moves over this set of radio buttons. If the shift key is pressed, the user wants to edit the script, so do nothing."
  7930.  
  7931.     | boxSize boxSpacing offset oldValue |
  7932.     boxSize _ checkBoxSize value.
  7933.     boxSpacing _ spacing value.
  7934.     ((editConstraint notNil) and: [editConstraint isSatisfied]) ifTrue:
  7935.         [(self boundingBox containsPoint: mousePoint) ifTrue:
  7936.             [offset _ (orientation value == #horizontal)
  7937.                 ifTrue: [mousePoint x - box left]
  7938.                 ifFalse: [mousePoint y - box top].
  7939.              ((offset \\ (boxSize + boxSpacing)) <= boxSize) ifTrue:
  7940.                 ["pointing to a box, change selection"
  7941.                  oldValue _ value value.
  7942.                  plan execute.
  7943.                  value value: (1 + (offset // (boxSize + boxSpacing))).
  7944.                  (value value ~= oldValue) ifTrue:
  7945.                     [self displayIn: view.
  7946.                      (compiledScript notNil) ifTrue:
  7947.                         [compiledScript value: view model value: view value: value value]]]]].!
  7948. handleMouseUp: mousePoint view: view
  7949.     "Clean up the edit constraint and plan."
  7950.  
  7951.     (editConstraint notNil) ifTrue:
  7952.         [editConstraint destroyConstraint.
  7953.          editConstraint _ nil.
  7954.          plan release.
  7955.          plan _ nil].!
  7956. wantsMouse
  7957.  
  7958.     ^true! !
  7959.  
  7960. AbstractButtonGlyph comment:
  7961. 'I define the general behavior of buttons. When the SceneController is in ''run'' mode, the button''s script will be invoked when the mouse is pressed and released inside my bounding box. The script which is just a sequence of expressions. A script is like a Smalltalk method except that it cannot have local variables. Scripts are compiled into blocks that are invoked when the button is pressed. Holding the shift key while pushing a button allows the script to be edited. Moving the cursor outside the button before releasing the mouse button aborts the operation.'!
  7962.  
  7963. !AbstractButtonGlyph methodsFor: 'initialize-release'!
  7964. initialize
  7965.  
  7966.     super initialize.
  7967.     lastMouseInButton _ false.! !
  7968.  
  7969. !AbstractButtonGlyph methodsFor: 'mouse'!
  7970. handleMouseDown: mousePoint view: view
  7971.     "If the shift key is pressed when the button is invoked, then edit the script immediately. Otherwise, give feedback and invoke the button script only if the mouse goes up inside the button."
  7972.  
  7973.     (Sensor leftShiftDown)
  7974.         ifTrue:
  7975.             [self editScript.
  7976.              lastMouseInButton _ false]
  7977.         ifFalse:
  7978.             [self reverseIn: view.
  7979.              lastMouseInButton _ true].!
  7980. handleMouseMove: mousePoint view: view
  7981.     "Show feedback. If the mouse is in the button, show it reversed."
  7982.  
  7983.     | mouseInButton |
  7984.     mouseInButton _ self containsPoint: mousePoint.
  7985.     (mouseInButton ~= lastMouseInButton) ifTrue:
  7986.         [self reverseIn: view.
  7987.          lastMouseInButton _ mouseInButton].!
  7988. handleMouseUp: mousePoint view: view
  7989.     "If the mouse is still in the button, then invoke or edit (if the shift key is pressed) the script. If the script is nil, it is not invoked."
  7990.  
  7991.     (self containsPoint: mousePoint) ifTrue:
  7992.         [lastMouseInButton ifTrue: [self reverseIn: view].
  7993.          (compiledScript notNil) ifTrue:
  7994.             [compiledScript value: view model value: view]].
  7995.     view displayScene.!
  7996. reverseIn: view
  7997.     "Show feedback by reversing. This toggles the reverse mode, so calling this method twice returns the display to its original state."
  7998.  
  7999.     Display reverse: 
  8000.         (self boundingBox translateBy: (view insetDisplayBox origin + view mouseOffset)).!
  8001. wantsMouse
  8002.  
  8003.     ^true! !
  8004.  
  8005. !AbstractButtonGlyph methodsFor: 'script'!
  8006. editScript
  8007.     "Edit my script. The script may reference the variables 'model' and 'view' as well as this glyph's instance variables."
  8008.  
  8009.     | newScript |
  8010.     newScript _ FillInTheBlank
  8011.         request:
  8012. 'Edit the script for this glyph. You many use the pseudovariables
  8013. ''model'' and ''view,'' as well as instance variables of this glyph.'
  8014.         initialAnswer: script.
  8015.  
  8016.     (newScript ~= script) ifTrue:
  8017.         [self script: newScript].!
  8018. script: scriptString
  8019.     "Compile and store the given script. The script may reference the variables 'model' and 'view,' as well as this glyph's instance variables."
  8020.  
  8021.     script _ scriptString.
  8022.     (scriptString isEmpty)
  8023.         ifTrue: [compiledScript _ nil]
  8024.         ifFalse:
  8025.             [compiledScript _ self compile:
  8026.                 ('[: model : view | ', scriptString, ']')].! !
  8027.  
  8028. AttachableButtonGlyph comment:
  8029. 'I can be used to attach a button to any real glyph. When the SceneController is in ''run'' mode, the button will be invoked when the mouse is pressed inside my host''s bounding box. The button has a script which is just a sequence of expressions. A script is like a Smalltalk method except that it cannot have local variables. Scripts are compiled into blocks that are invoked when the button is pressed.'!
  8030.  
  8031. !AttachableButtonGlyph methodsFor: 'initialize-release'!
  8032. forHost: aGlyph
  8033.  
  8034.     super initialize.
  8035.     host _ aGlyph.! !
  8036.  
  8037. !AttachableButtonGlyph methodsFor: 'accessing'!
  8038. host
  8039.  
  8040.     ^host! !
  8041.  
  8042. !AttachableButtonGlyph methodsFor: 'glyph protocol'!
  8043. boundingBox
  8044.  
  8045.     ^host boundingBox!
  8046. locationPoints
  8047.  
  8048.     self error: 'Only my host should be moved'! !
  8049.  
  8050. !AttachableButtonGlyph methodsFor: 'enumeration'!
  8051. includesObjectIn: objectList
  8052.     "Answer true if either I or my host is in the given list."
  8053.  
  8054.     ^(objectList includes: host) or:
  8055.       [objectList includes: self]!
  8056. inputGlyphsDo: aBlock
  8057.     "I am an input glyph."
  8058.  
  8059.     aBlock value: self.!
  8060. selectableGlyphsDo: aBlock
  8061.     "I have none."!
  8062. varsDo: aBlock
  8063.     "I have none."!
  8064. visibleGlyphsDo: aBlock
  8065.     "I have none."! !
  8066.  
  8067. !AttachableButtonGlyph methodsFor: 'script'!
  8068. compile: aString
  8069.     "Answer the evaluation of the given code string (which is usually a block). The code is evaluated in the context of my host, so it may access the host's instance variables."
  8070.  
  8071.     ^Compiler
  8072.         evaluate: aString
  8073.         for: host
  8074.         logged: false! !
  8075.  
  8076. !TextGlyph methodsFor: 'initialize-release'!
  8077. initialize
  8078.  
  8079.     super initialize.
  8080.     box _ RectangleGlyph new.
  8081.     text _ FreeVariable value: 'a TextGlyph'.
  8082.     font _ FreeVariable value: (TextStyle default fontAt: 1).
  8083.     (WidthC == nil) ifTrue:
  8084.         [WidthC _ Constraint
  8085.             names: #(width text font)
  8086.             methods: #('width _ QuickPrint width: text inFont: font')].
  8087.     (HeightC == nil) ifTrue:
  8088.         [HeightC _ Constraint
  8089.             names: #(height font)
  8090.             methods: #('height _ font height')].
  8091.     (WidthC copy) var: (box widthVar) var: (text) var: (font) strength: #required.
  8092.     (HeightC copy) var: (box heightVar) var: (font) strength: #required.! !
  8093.  
  8094. !TextGlyph methodsFor: 'accessing'!
  8095. box
  8096.  
  8097.     ^box!
  8098. font
  8099.  
  8100.     ^font value!
  8101. font: aStrikeFont
  8102.  
  8103.     font setValue: aStrikeFont.!
  8104. fontVar
  8105.  
  8106.     ^font!
  8107. text
  8108.  
  8109.     ^text value!
  8110. text: aString
  8111.  
  8112.     text setValue: aString.!
  8113. textVar
  8114.  
  8115.     ^text! !
  8116.  
  8117. !TextGlyph methodsFor: 'glyph protocol'!
  8118. boundingBox
  8119.     "Answer my bounding box."
  8120.  
  8121.     ^((box left - 1)@(box top - 1)) corner:
  8122.         ((box right + 1)@(box bottom + 1))!
  8123. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  8124.     "Display myself."
  8125.  
  8126.     | scanner |
  8127.     scanner _ QuickPrint
  8128.         newOn: aDisplayMedium
  8129.         box: ((aDisplayPoint + (box left@box top)) corner: clipBox bottomRight)
  8130.         font: font value.
  8131.     scanner drawString: text value.!
  8132. isSelectable
  8133.  
  8134.     ^true!
  8135. locationPoints
  8136.  
  8137.     ^Array with: box center! !
  8138.  
  8139. !TextGlyph methodsFor: 'enumeration'!
  8140. selectableGlyphsDo: aBlock
  8141.     "None of my subparts is selectable."
  8142.  
  8143.     aBlock value: self.!
  8144. visibleGlyphsDo: aBlock
  8145.     "None of my subparts is visible."
  8146.  
  8147.     aBlock value: self.! !
  8148.  
  8149. !TextGlyph methodsFor: 'keyboard'!
  8150. handleKeystroke: aCharacter view: aView
  8151.     "Handle a keystroke. If the character is a backspace, then remove one character from my text. Otherwise, append the character to my text."
  8152.  
  8153.     | backspace myText |
  8154.     backspace _ 8 asCharacter.
  8155.     myText _ text value.
  8156.     (aCharacter = backspace)
  8157.         ifTrue:
  8158.             [(myText size > 0) ifTrue:
  8159.                 [text value: (myText copyFrom: 1 to: myText size - 1)]]
  8160.         ifFalse: [text value: (myText copyWith: aCharacter)].!
  8161. keystrokeVars
  8162.  
  8163.     ^Array with: text!
  8164. wantsKeystrokes
  8165.  
  8166.     ^true! !
  8167.  
  8168. TextButtonGlyph comment:
  8169. 'Here''s a place multiple inheritance would be handy. A TextButtonGlyph is like both a TextGlyph and an AbstractButtonGlyph. We''ve chosen to make it a subclass of AbstractButtonGlyph and re-implemented the behavior of TextGlyph.'!
  8170.  
  8171. !TextButtonGlyph methodsFor: 'initialize-release'!
  8172. initialize
  8173.  
  8174.     super initialize.
  8175.     text setValue: 'Button'.
  8176.     font setValue: (TextStyle default fontAt: 14).
  8177.     button _ AttachableButtonGlyph forHost: self.
  8178.     cachedText _ ''.
  8179.     formCache _ nil.! !
  8180.  
  8181. !TextButtonGlyph methodsFor: 'accessing'!
  8182. script: aString
  8183.     "Compile the given script for me."
  8184.  
  8185.     button script: aString.! !
  8186.  
  8187. !TextButtonGlyph methodsFor: 'glyph protocol'!
  8188. boundingBox
  8189.     "Answer my bounding box."
  8190.  
  8191.     ^((box left - 7)@(box top - 6)) corner:
  8192.         ((box right + 6)@(box bottom + 5))!
  8193. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  8194.     "Display myself."
  8195.  
  8196.     | scanner |
  8197.     scanner _ QuickPrint
  8198.         newOn: aDisplayMedium
  8199.         box: ((aDisplayPoint + (box left@box top)) corner: clipBox bottomRight)
  8200.         font: font value.
  8201.     scanner drawString: text value.
  8202.     aDisplayMedium
  8203.         border:
  8204.             ((((box left - 5)@(box top - 4)) corner:
  8205.              ((box right + 4)@(box bottom + 3))) moveBy: aDisplayPoint)
  8206.         widthRectangle: (2@2 corner: 2@2)
  8207.         mask: (Form black)
  8208.         clippingBox: clipBox! !
  8209.  
  8210. !BoxTextGlyph methodsFor: 'glyph protocol'!
  8211. boundingBox
  8212.     "Answer my bounding box."
  8213.  
  8214.     ^((box left - 4)@(box top - 4)) corner:
  8215.         ((box right + 4)@(box bottom + 4))!
  8216. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox
  8217.     | scanner  r |
  8218.     r _ box asRectangle moveBy: aDisplayPoint.
  8219.     scanner _ QuickPrint
  8220.         newOn: aDisplayMedium
  8221.         box: ((r topLeft) corner: clipBox bottomRight)
  8222.         font: font value.
  8223.     aDisplayMedium fill: (r insetBy: -1 @ -1) mask: Form white.
  8224.     aDisplayMedium border: (r insetBy: -3 @ -3)
  8225.         width: 2.
  8226.     scanner drawString: text value.! !
  8227.  
  8228. !MacDrawRulerGlyph methodsFor: 'glyph protocol'!
  8229. displayOn: aDisplayMedium at: aDisplayPoint clip: clipBox 
  8230.     | left right bottom littles |
  8231.     left _ MacDrawDemo leftEdge.
  8232.     right _ MacDrawDemo rightEdge.
  8233.     bottom _ MacDrawDemo dragTop - 20.
  8234.     littles _ Array
  8235.                 with: (Array with: 12.5 with: bottom - 5)
  8236.                 with: (Array with: 25 with: bottom - 10)
  8237.                 with: (Array with: 100 with: bottom - 25).
  8238.     self
  8239.         hLineFrom: left @ bottom
  8240.         length: right - left
  8241.         on: aDisplayMedium
  8242.         at: aDisplayPoint
  8243.         clip: clipBox.
  8244.     littles do: [:each | left
  8245.             to: right
  8246.             by: (each at: 1)
  8247.             do: [:x | self
  8248.                     vLineFrom: x @ (each at: 2)
  8249.                     length: bottom - (each at: 2)
  8250.                     on: aDisplayMedium
  8251.                     at: aDisplayPoint
  8252.                     clip: clipBox]]!
  8253. isSelectable
  8254.     ^false!
  8255. locationPoints
  8256.     ^Array with: MacDrawDemo leftEdge @ MacDrawDemo dragTop! !
  8257.  
  8258. !ClassReorgChange methodsFor: 'accessing'!
  8259. text
  8260.     file position: position.
  8261.     ^className, ' reorganize
  8262. ', file nextChunk! !
  8263.  
  8264. !ClassReorgChange methodsFor: 'fileIn/Out'!
  8265. fileOutOn: aStream
  8266.     file position: position.
  8267.     aStream nextPut: $!!.
  8268.     aStream nextChunkPut: (className, ' reorganize') ; cr.
  8269.     aStream nextChunkPut: file nextChunk ; cr ; cr.! !
  8270.  
  8271. !Form methodsFor: 'fileIn/Out'!
  8272. writeMacPaint: fileName
  8273.     "Saves the receiver on the file fileName in MacPaint format."
  8274.     "Form fromUser writeMacPaint: 'form.paint'"
  8275.  
  8276.     "The first 512 bytes of the file are the header. The first four bytes
  8277.     comprise the version number, followed by 38*8 = 304 bytes of       
  8278.     patterns.  The remaining 204 bytes of the header are reserved for
  8279.     future expansion. If the version number is zero, the patterns are     
  8280.     ignored. Hence, programs that wish to create files to be read into
  8281.     MACpaint can just write out 512 bytes of zero as the header.       
  8282.             
  8283.     Following the header are 720 compressed scanlines of data which
  8284.     form the 576 wide by 720 tall bitmap. The bitmap is compressed as 
  8285.     follows:      
  8286.         Any run of three or more equal bytes is compressed into a count       
  8287.         byte and a single data byte. Runs of unequal bytes are passed
  8288.         on literally, preceded also by a count byte, i.e.:      
  8289.             
  8290.         <count byte> <data byte>         count = -1..-127 --> replicate byte 2..128 times       
  8291.         <count byte> <n data bytes>     count =  0.. 127 --> copy 1..128 bytes  
  8292.          uncompressed                        count = -128 ignored for backward compatibility."
  8293.  
  8294.  
  8295.  
  8296.     | file loopIndex rasterNum wordWidth maxHeight formIndex maxFormWordWidth |
  8297.     SystemCall setCreator: 'MPNT' andType: 'PNTG'. 
  8298.     file _ FileStream fileNamed: fileName.
  8299.     file binary.
  8300.     wordWidth _ width +15 // 16.
  8301.     width    < 576 ifTrue: [maxFormWordWidth _ width +15 // 16]    ifFalse: [maxFormWordWidth _ 36].
  8302.     height    < 720 ifTrue: [maxHeight _ height]                        ifFalse: [maxHeight _ 720].
  8303.     loopIndex _ 1.
  8304.     [loopIndex <= 512] whileTrue: [file nextPut: 0. loopIndex _ loopIndex + 1].
  8305.     rasterNum _ 1.
  8306.     formIndex _ 1.
  8307.     [rasterNum <= maxHeight] whileTrue: 
  8308.         [file nextPut: 71. 
  8309.         loopIndex _ 1.
  8310.         formIndex _ ((rasterNum - 1) * wordWidth) + 1.
  8311.         [loopIndex <= maxFormWordWidth] whileTrue: 
  8312.             [file nextWordPut: (bits at: formIndex). 
  8313.             formIndex    _ formIndex    + 1.
  8314.             loopIndex    _ loopIndex    + 1].
  8315.         "loopIndex <= 35 ifTrue: [file nextPut: (255 - 72 - (loopIndex * 2)) asInteger. file nextPut: 0.]."
  8316.         [loopIndex <= 36] whileTrue: [file nextWordPut: 0. loopIndex _ loopIndex + 1].
  8317.         rasterNum _ rasterNum + 1].
  8318.  
  8319.     "If the MacPaint file needs to be padded with blank rasters at the bottom of the picture,
  8320.     then pad it with compressed blank rasters..."
  8321.     [rasterNum <= 720] whileTrue: 
  8322.         [file nextPut: 185.
  8323.         file nextPut: 0.    
  8324.         rasterNum _ rasterNum + 1].
  8325.  
  8326.     file close.
  8327.     SystemCall resetCreatorAndType! !
  8328.  
  8329. !ParagraphEditor class methodsFor: 'selection access'!
  8330. addPreviousSelection: aText
  8331.     "NOTE: copied for my instance protocol for support of storePasteText:"
  8332.     "Save away a selection for use by leftShift-paste. Don't save it if it's 
  8333.     already on the list, or if it is all white space. Save only a few."
  8334.  
  8335.     (PreviousSelections includes: aText)
  8336.         ifTrue: [^self].
  8337.     (aText detect: [:char | char isSeparator not] ifNone: [nil]) == nil
  8338.         ifTrue: [^self].
  8339.     PreviousSelections size >= 5 ifTrue: [PreviousSelections removeLast].
  8340.     PreviousSelections addFirst: aText!
  8341. storePasteText: aString
  8342.     "Allows one to put text into the paste buffer from other applications. For example, a form editor can stuff a textual representation of the form into the paste buffer allowing the user to insert it into a method."
  8343.  
  8344.     CurrentSelection _ aString asText.
  8345.     self addPreviousSelection: CurrentSelection! !
  8346.  
  8347. !StringHolderController class methodsFor: 'class initialization'!
  8348. initialize
  8349.     "Initialize the yellow button pop-up menu and corresponding messages."
  8350.     "StringHolderController initialize"
  8351.  
  8352.     CodeYellowButtonMenu _ 
  8353.         PopUpMenu 
  8354.             labelList: #((again undo) (copy cut paste) ('do it' 'print it' inspect) (accept cancel) ('edit form')).
  8355.     CodeYellowButtonMessages _ 
  8356.         #(again undo copySelection cut paste doIt printIt inspectIt accept cancel formEdit)! !
  8357.  
  8358. Midi class comment:
  8359. 'Midi - Musical Instrument Digital Interface
  8360.  
  8361. This class allows Smalltalk programs to control synthesizers and other musical devices attached via the RS232 port and a midi interface box. Because the Midi port(s) are a shared resource, there are no instances of this class. Instead, Midi control messages are directed to the class itself. You can use the "class refs" facility to find all the users of Midi operations in the system.
  8362. -----------------------------------------------------------------------
  8363. Notes on the Smalltalk Midi Primitives
  8364.  
  8365. 1. Be sure to have a Midi interface attached the port you are using. The interface should have a clock speed of 1 Mhz (most do, including the one from Apple). It is possible to hang the system if you open a port that does not have a Midi interface attached (and turned on) because the port depends on a clock signal supplied by the Midi interface -- no clock, no action!!!!
  8366.  
  8367. 2. The Midi driver is interrupt driven and the interrupt code is part of the Smalltalk interpreter. Thus, if you quit from Smalltalk with one of the Midi ports open and an interrupt occurs (due to a character arriving, say) then your Mac will crash because the drivers aren''t there anymore. Included in this filein is a modification of Smalltalk''s quit method that closes all Midi ports. (Closing a non-open port is harmless.) It is recommended that you include a similar mechanism in any applications you develop yourself. You will have to re-open the Midi port(s) you were using after restarting the image.
  8368.  
  8369. 3. There is a limit of 1000 bytes per call to the Midi put primitive; you can pass it a bigger buffer but the extra bytes will not be sent.
  8370.  
  8371. 4. The Midi "put" primitive puts its bytes in an internal buffer until all previous bytes have been sent. If there is not enough room in the buffer, the put primitive waits until there is room. If there IS room in in the buffer, the bytes of the current call are buffered and the call returns to Smalltalk immediately even though not all the bytes have actually been sent.
  8372.  
  8373. 5. If the transmit buffer is completely full, it takes nearly three seconds to empty itself. (Midi data is sent at 3125 bytes/second, so you have to send a lot of data fast to actually fill up the 8192 byte transmit buffer.) If you close the Midi port before the buffer is empty, some bytes will never be sent. My practice is to keep the Midi port open continuously during a Smalltalk session but if your application opens and closes the port dynamically, you may wish to insert a three second delay before each close operation to absolutely guarantee that all the bytes have been sent.
  8374. '!
  8375.  
  8376. !Midi class methodsFor: 'initialize-debug'!
  8377. debugOff
  8378.     "Midi debugOff"
  8379.  
  8380.     Debug _ false.!
  8381. debugOn
  8382.     "When the debugging switch is turned on, all midi output will be printed to the Transcript rather than actually sent. Debugging also enables range checks on the parameters of the outgoing Midi messages."
  8383.     "Midi debugOn"
  8384.  
  8385.     Debug _ true.!
  8386. initialize
  8387.     "Midi initialize"
  8388.  
  8389.     Debug _ false.
  8390.     InBuf _ BufferStream on: (ByteArray new: 100).
  8391.     Port _ nil.
  8392.     self primClose: 0.
  8393.     self primClose: 1.
  8394.     Smalltalk removeDependent: self.! !
  8395.  
  8396. !Midi class methodsFor: 'port control'!
  8397. closePort
  8398.     "Close the midi port."
  8399.     "Midi closePort"
  8400.  
  8401.     Smalltalk removeDependent: self.
  8402.     (Port isNil) ifFalse: [self primClose: Port].
  8403.     Port _ nil.!
  8404. openPort: portNumber
  8405.     "Open the given midi port. In case the port is currently open, close it first."
  8406.     "Midi openPort"
  8407.  
  8408.     self closePort.
  8409.     Port _ portNumber.
  8410.     Smalltalk addDependent: self.
  8411.     self primOpen: portNumber.!
  8412. update: parameter
  8413.     "Close the port if the user quits Smalltalk to avoid hanging the system."
  8414.  
  8415.     ((parameter == #aboutToSnapshotAndQuit) | (parameter == #aboutToQuit))
  8416.         ifTrue: [self closePort].! !
  8417.  
  8418. !Midi class methodsFor: 'midi output'!
  8419. allNotesOff
  8420.     "Turns off all midi notes on all midi channels."
  8421.  
  8422.     1 to: 16 do: [: ch | self control: 123 value: 0 chan: ch].!
  8423. control: control value: value chan: channel
  8424.     "Sets the given control to the given new value."
  8425.  
  8426.     self send: 176 with: control with: value on: channel.!
  8427. noteOff: key chan: channel
  8428.     "Turns off the given note."
  8429.     "Detail: Send a 'noteOn' command with zero velocity since not all synthesizers recognize the 'noteOff' command."
  8430.  
  8431.     self send: 144 with: key with: 0 on: channel.!
  8432. noteOn: key vel: velocity chan: channel
  8433.     "Turns on the given note."
  8434.  
  8435.     self send: 144 with: key with: velocity on: channel.!
  8436. pitchBend: bend chan: channel
  8437.     "Updates the pitch bend on this channel to the given new value."
  8438.  
  8439.     self
  8440.         send: 224
  8441.         with: (bend bitAnd: 127)
  8442.         with: (bend bitShift: -7)
  8443.         on: channel.!
  8444. program: program chan: channel
  8445.     "Changes the synthesizer's 'program number' (or 'instrument' or 'preset') for this channel to the given new value."
  8446.  
  8447.     self send: 192 with: (program - 1) on: channel.!
  8448. synthInit
  8449.     "Resets the synthesizer. This may need to be changed since devices differ; the idea is to put the synthesizer into a known state for all parameters which might be changed through Midi."
  8450.  
  8451.     1 to: 16 do:
  8452.         [: channel |
  8453.             self control: 123 value: 0 chan: channel.    "All notes off on this channel."
  8454.             self pitchBend: 8192 chan: channel.
  8455.             self program: 1 chan: channel.
  8456.             "You may wish to reset various other control values here."].! !
  8457.  
  8458. !Midi class methodsFor: 'midi monitor'!
  8459. monitor
  8460.     "This is a simple midi monitor program which deciphers incoming
  8461.     midi commands and prints them to the transcript until a mouse
  8462.     button is pressed."
  8463.     "Midi monitor"
  8464.  
  8465.     self monitorAllBut: #().!
  8466. monitorAllBut: cmdList
  8467.     "Print midi messages to the transcript until any mouse button is pressed.
  8468.     Ignore the given collection of command bytes."
  8469.  
  8470.     | recorder |
  8471.     recorder _ MidiRecorder new.
  8472.     cmdList do: [: cmd | recorder ignoreCmd: cmd].    "ignore these commands"
  8473.     recorder monitor.!
  8474. monitorRaw
  8475.     "Shows the raw midi data as decimal bytes as it arrives. Suppresses printing of 'active status' bytes."
  8476.     "Midi monitorRaw"
  8477.  
  8478.     | c |
  8479.     self flushInput.
  8480.     [Sensor anyButtonPressed] whileFalse:
  8481.         [c _ self getByte.
  8482.          ((c ~= #NoInput) & (c ~= 254))
  8483.             ifTrue: [Transcript show: c printString, ' ']].! !
  8484.  
  8485. !Midi class methodsFor: 'low level - output'!
  8486. putByte: aByte
  8487.     "Sends aByte to the Midi device."
  8488.  
  8489.     Debug
  8490.         ifTrue: [Transcript show: aByte printString; cr]
  8491.         ifFalse:
  8492.             [(Port isNil) ifTrue: [^self error: 'Midi port not open'].
  8493.              self primPut: Port bytes: (ByteArray with: aByte) count: 1].!
  8494. send: midiCode with: arg on: channel
  8495.     "Sends a one-argument midi channel message. Checks midiCode, argument, and channel number if Debug is true."
  8496.  
  8497.     | cmd |
  8498.     cmd _ midiCode bitOr: (channel - 1).
  8499.     Debug
  8500.         ifTrue:
  8501.             [((midiCode >= 128) & (midiCode <= 255))
  8502.                 ifFalse: [self error: 'bad Midi command'].
  8503.              ((channel >= 1) & (channel <= 16))
  8504.                 ifFalse: [self error: 'bad channel number'].
  8505.              ((arg >= 0) & (arg <= 127))
  8506.                 ifFalse: [self error: 'bad Midi argument'].
  8507.              Transcript show:
  8508.                 cmd printString, ' ',
  8509.                 arg printString; cr]
  8510.         ifFalse:
  8511.             [(Port isNil) ifTrue: [^self error: 'Midi port not open'].
  8512.              self
  8513.                 primPut: Port
  8514.                 bytes: (ByteArray with: cmd with: arg)
  8515.                 count: 2].!
  8516. send: midiCode with: arg1 with: arg2 on: channel
  8517.     "Sends a two-argument midi channel message. Checks midiCode, arguments, and channel number if Debug is true."
  8518.  
  8519.     | cmd |
  8520.     cmd _ midiCode bitOr: (channel - 1).
  8521.     Debug
  8522.         ifTrue:
  8523.             [((midiCode >= 128) & (midiCode <= 255))
  8524.                 ifFalse: [self error: 'bad Midi command'].
  8525.              ((channel >= 1) & (channel <= 16))
  8526.                 ifFalse: [self error: 'bad channel number'].
  8527.              ((arg1 >= 0) & (arg1 <= 127))
  8528.                 ifFalse: [self error: 'bad Midi argument'].
  8529.              ((arg2 >= 0) & (arg2 <= 127))
  8530.                 ifFalse: [self error: 'bad Midi argument'].
  8531.              Transcript show:
  8532.                 cmd printString, ' ',
  8533.                 arg1 printString, ' ',
  8534.                 arg2 printString; cr]
  8535.         ifFalse:
  8536.             [(Port isNil) ifTrue: [^self error: 'Midi port not open'].
  8537.              self
  8538.                 primPut: Port
  8539.                 bytes: (ByteArray with: cmd with: arg1 with: arg2)
  8540.                 count: 3].! !
  8541.  
  8542. !Midi class methodsFor: 'low level - input'!
  8543. flushInput
  8544.     "Empty the midi port's input buffer."
  8545.  
  8546.     self getBuffer.
  8547.     [InBuf atEnd] whileFalse:
  8548.         ["suck in buffers until there is no more data in the queue"
  8549.          self getBuffer].!
  8550. getBuffer
  8551.     "Refills InBuf from the midi port."
  8552.  
  8553.     | buf count |
  8554.     (Port isNil) ifTrue: [^self error: 'Midi port not open'].
  8555.     InBuf resetAll.
  8556.     buf _ InBuf buffer.
  8557.     count _ self primGet: Port bytes: buf size: buf size.
  8558.     InBuf setReadLimit: count.!
  8559. getByte
  8560.     "Gets next input byte without waiting. Answers #NoInput if there isn't any."
  8561.  
  8562.     (Debug | Port isNil)
  8563.         ifTrue: [^#NoInput]
  8564.         ifFalse:
  8565.             [(InBuf atEnd) ifTrue: [self getBuffer].    "get more input data"
  8566.              (InBuf atEnd)    "nothing?"
  8567.                 ifTrue:  [^#NoInput]
  8568.                 ifFalse: [^InBuf next]].!
  8569. readStream
  8570.  
  8571.     self getBuffer.
  8572.     ^InBuf! !
  8573.  
  8574. !Midi class methodsFor: 'primitive tests'!
  8575. noopTest
  8576.     "Midi noopTest"
  8577.  
  8578.     ^Time millisecondsToRun:
  8579.         [1000 timesRepeat: [self primNoop]]!
  8580. openCloseTest
  8581.     "Midi openCloseTest"
  8582.  
  8583.     self primOpen: 0.
  8584.     self primClose: 0.!
  8585. receiveTest
  8586.     "Receive for 5 seconds from to midi port 0."
  8587.     "Midi receiveTest"
  8588.  
  8589.     | bytes count startTime |
  8590.     bytes _ ByteArray new: 1000.
  8591.     count _ 0.
  8592.     startTime _ Time millisecondClockValue.
  8593.     self primOpen: 0.
  8594.     [(Time millisecondClockValue - startTime) < 5000]
  8595.         whileTrue:
  8596.             [count _ count +
  8597.                 (self primGet: 0 bytes: bytes size: 1000)].
  8598.     self primClose: 0.
  8599.     ^count!
  8600. sendTest
  8601.     "Send 10000 bytes to midi port 0."
  8602.     "Midi sendTest"
  8603.  
  8604.     | bytes time |
  8605.     bytes _ ByteArray new: 1000 withAll: 248. "Midi clock byte"
  8606.     self primOpen: 0.
  8607.     time _ Time millisecondsToRun: [
  8608.         1000 timesRepeat:
  8609.             [self primPut: 0 bytes: bytes count: 10]].
  8610.     self primClose: 0.
  8611.     ^time! !
  8612.  
  8613. !Midi class methodsFor: 'primitives'!
  8614. primClose: portNumber
  8615.  
  8616.     <primitive: -2>
  8617.     self primitiveFailed.!
  8618. primGet: portNumber bytes: aByteArray size: aNumber
  8619.  
  8620.     <primitive: -4>
  8621.     self primitiveFailed.!
  8622. primNoop
  8623.  
  8624.     <primitive: -5>
  8625.     self primitiveFailed.!
  8626. primOpen: portNumber
  8627.  
  8628.     <primitive: -1>
  8629.     self primitiveFailed.!
  8630. primPut: portNumber bytes: aByteArray count: aNumber
  8631.  
  8632.     <primitive: -3>
  8633.     self primitiveFailed.! !
  8634.  
  8635. !Glyph class methodsFor: 'instance creation'!
  8636. new
  8637.  
  8638.     ^self basicNew initialize! !
  8639.  
  8640. !Glyph class methodsFor: 'classification'!
  8641. glyphCategory
  8642.     "Answer the category name for this glyph. By default, all glyphs are placed in the 'unclassified' category. Subclasses should override this method to put themselves in a more suggestively named category. If the category string is empty, the glyph is not presented at all. This is used to hide abstract superclass glyphs."
  8643.  
  8644.     ^'Unclassified'! !
  8645.  
  8646. !Glyph class methodsFor: 'constraint release'!
  8647. releaseConstraints
  8648.     "Used to destroy constraint prototypes stored in class variables. Glyph classes that store constraint prototypes store in class variables should override this message to destroy these constraints. The method objects in these constraints may contain BlockContext's that hold onto pointers to garbage in Smalltalk version 2.3. To get rid of this garbage, do:
  8649.  
  8650.     Glyph withAllSubclasses do: [: glyphClass | glyphClass releaseConstraints]"! !
  8651.  
  8652. !ScriptGlyph class methodsFor: 'classification'!
  8653. glyphCategory
  8654.  
  8655.     ^''! !
  8656.  
  8657. !TwoProngTextGlyph class methodsFor: 'classification'!
  8658. glyphCategory
  8659.     ^'SIGGRAPH'! !
  8660.  
  8661. !TwoProngTextGlyph class methodsFor: 'constraint release'!
  8662. releaseConstraints
  8663.     "TwoProngTextGlyph releaseConstraints"
  8664.  
  8665.     CenterOffsetConstraint _ nil! !
  8666.  
  8667. !RadioButtonsGlyph class methodsFor: 'classification'!
  8668. glyphCategory
  8669.  
  8670.     ^'Widgets'! !
  8671.  
  8672. !RadioButtonsGlyph class methodsFor: 'constraint release'!
  8673. releaseConstraints
  8674.  
  8675.     HeightC _ nil.
  8676.     WidthC _ nil.! !
  8677.  
  8678. !ThermometerGlyph class methodsFor: 'class initialization'!
  8679. initialize
  8680.     "ThermometerGlyph initialize."
  8681.  
  8682.     BulbForm _ Form
  8683.                 extent: 30 @ 30
  8684.                 fromArray: #(1706 43712 1365 21824 1706 43712 1365 21824 1706 43712 3413 21856 6826 43696 13653 21840 10922 43704 13653 21848 10922 43688 30037 21852 27306 43692 54613 21844 43690 43692 54613 21844 60074 43692 21845 21844 27306 43692 13653 21848 10922 43704 13653 21840 6826 43696 3413 21856 1706 43712 853 21888 426 43776 213 22016 127 64512 0 0 )
  8685.                 offset: 0 @ 0.
  8686.     BulbForm2 _ (Form
  8687.     extent: 30@30
  8688.     fromArray: #( 1706 43712 1365 21824 1706 43712 1365 21824 1706 43712 3413 21856 6826 43696 13653 21840 10922 43704 13653 22520 10922 43520 30079 22016 27361 44032 57281 22528 43009 45060 55296 57356 59392 796 22648 2036 29167 3756 341 40280 938 64184 8021 21840 6826 43696 3413 21856 1706 43712 853 21888 426 43776 213 22016 127 64512 0 0)
  8689.     offset: 0@0).
  8690.     CapForm _ (Form
  8691.     extent: 41@29
  8692.     fromArray: #( 0 0 0 0 0 0 32263 33249 61184 32527 50161 65280 25500 59193 47872 24984 26137 47872 25496 26137 33536 32536 26137 33536 32536 26137 33536 25496 26137 33536 24984 26137 33536 25500 59161 33536 32527 50161 33536 32263 33249 33536 0 0 0 43176 2082 35328 21585 21765 5376 43682 43690 10752 5461 17749 21504 2730 2600 43008 4437 21841 21504 674 43690 32768 341 21781 16384 682 43690 40960 341 17749 16384 42 43688 0 85 21844 0 10 43688 0 21 21844 0)
  8693.     offset: 0@0)! !
  8694.  
  8695. !ThermometerGlyph class methodsFor: 'internal'!
  8696. internalMsg1: minVar and: maxVar and: tempVar and: boxHeightVar and: boxTopVar
  8697.     | scaleFactor markY |
  8698.     scaleFactor _ boxHeightVar  asFloat / (maxVar  - minVar ) asFloat.
  8699.     markY _ (scaleFactor * (tempVar  asFloat - minVar  asFloat)) rounded.
  8700.     markY _ (markY max: 0)
  8701.                 min: boxHeightVar.
  8702.     markY _ boxHeightVar - markY + boxTopVar.
  8703.     ^markY!
  8704. internalMsg2: tempVar and: over
  8705.     ^tempVar > over!
  8706. internalMsg3: tempVar and: under
  8707.     ^tempVar < under! !
  8708.  
  8709. !ThermometerGlyph class methodsFor: 'constraint release'!
  8710. releaseConstraints
  8711.     "ThermometerGlyph releaseConstraints"
  8712.  
  8713.     PrintConstraint _ MercConstraint _ OverConstraint _ UnderConstraint _ nil! !
  8714.  
  8715. !ThermometerGlyph class methodsFor: 'classification'!
  8716. glyphCategory
  8717.     ^'SIGGRAPH'! !
  8718.  
  8719. !ThreeProngTextGlyph class methodsFor: 'classification'!
  8720. glyphCategory
  8721.     ^'SIGGRAPH'! !
  8722.  
  8723. !ThreeProngTextGlyph class methodsFor: 'constraint release'!
  8724. releaseConstraints
  8725.     "ThreeProngTextGlyph releaseConstraints"
  8726.  
  8727.     CenterOffsetConstraint _ nil! !
  8728.  
  8729. !AbstractButtonGlyph class methodsFor: 'classification'!
  8730. glyphCategory
  8731.  
  8732.     ^''! !
  8733.  
  8734. !AttachableButtonGlyph class methodsFor: 'instance creation'!
  8735. forHost: aGlyph
  8736.  
  8737.     ^self basicNew forHost: aGlyph!
  8738. new
  8739.  
  8740.     ^self error: 'Use ''forHost:'' to make new instances'! !
  8741.  
  8742. !AttachableButtonGlyph class methodsFor: 'classification'!
  8743. glyphCategory
  8744.  
  8745.     ^''! !
  8746.  
  8747. !HSliderGlyph class methodsFor: 'instance creation'!
  8748. on: aVariable
  8749.     "Create a new slider on the given variable."
  8750.  
  8751.     | slider |
  8752.     slider _ self new value: (aVariable value).
  8753.     slider valueVar requireEquals: aVariable.
  8754.     ^slider! !
  8755.  
  8756. !HSliderGlyph class methodsFor: 'classification'!
  8757. glyphCategory
  8758.  
  8759.     ^'Widgets'! !
  8760.  
  8761. !HSliderGlyph class methodsFor: 'constraint release'!
  8762. releaseConstraints
  8763.  
  8764.     HeightC _ nil.
  8765.     WidthC _ nil.! !
  8766.  
  8767. !AttachableMenuGlyph class methodsFor: 'instance creation'!
  8768. forHost: aGlyph
  8769.  
  8770.     ^self basicNew forHost: aGlyph!
  8771. new
  8772.  
  8773.     ^self error: 'Use ''forHost:'' to make new instances'! !
  8774.  
  8775. !AttachableMenuGlyph class methodsFor: 'classification'!
  8776. glyphCategory
  8777.  
  8778.     ^''! !
  8779.  
  8780. !TextGlyph class methodsFor: 'classification'!
  8781. glyphCategory
  8782.  
  8783.     ^'General'! !
  8784.  
  8785. !TextGlyph class methodsFor: 'constraint release'!
  8786. releaseConstraints
  8787.  
  8788.     HeightC _ nil.
  8789.     WidthC _ nil.! !
  8790.  
  8791. !TextButtonGlyph class methodsFor: 'classification'!
  8792. glyphCategory
  8793.  
  8794.     ^'Widgets'! !
  8795.  
  8796. !BoxTextGlyph class methodsFor: 'classification'!
  8797. glyphCategory
  8798.     ^'SIGGRAPH'! !
  8799.  
  8800. !MacDrawRulerGlyph class methodsFor: 'classification'!
  8801. glyphCategory
  8802.     ^'SIGGRAPH'! !
  8803.  
  8804. !MacDrawDashGlyph class methodsFor: 'classification'!
  8805. glyphCategory
  8806.     ^'SIGGRAPH'! !
  8807.  
  8808. !MacDrawDashGlyph class methodsFor: 'constraint release'!
  8809. releaseConstraints
  8810.     "MacDrawDashGlyph releaseConstraints"
  8811.  
  8812.     LengthConstraint _ nil! !
  8813.  
  8814. !TransistorGlyph class methodsFor: 'classification'!
  8815. glyphCategory
  8816.  
  8817.     ^'Electronic'! !
  8818.  
  8819. !NoteBarGlyph class methodsFor: 'class initialization'!
  8820. initialize
  8821.     "NoteBarGlyph initialize; showForms"
  8822.  
  8823.     Forms _ Dictionary new.
  8824.     Forms at: #normal put: (Form
  8825.         extent: 1@1
  8826.         fromArray: #(0)
  8827.         offset: 0@0).
  8828.     Forms at: #sharp put: (Form
  8829.         extent: 5@17
  8830.         fromArray: #(4096 20480 20480 22528 30720 63488 61440 53248 20480 22528 30720 63488 61440 53248 20480 20480 16384)
  8831.         offset: 0@-9).
  8832.     Forms at: #dSharp put: (Form
  8833.         extent: 5@6
  8834.         fromArray: #(55296 55296 28672 28672 55296 55296)
  8835.         offset: 0@2).
  8836.     Forms at: #flat put: (Form
  8837.         extent: 4@13
  8838.         fromArray: #(32768 32768 32768 32768 32768 32768 32768 45056 61440 36864 45056 49152 32768)
  8839.         offset: 0@-5).
  8840.     Forms at: #dFlat put: (Form
  8841.         extent: 7@15
  8842.         fromArray: #(36864 36864 36864 36864 36864 36864 36864 36864 46080 65024 46592 46592 64512 55296 36864)
  8843.         offset: 0@-7).
  8844.     Forms at: #natural put: (Form
  8845.         extent: 4@15
  8846.         fromArray: #(32768 32768 32768 32768 45056 61440 53248 36864 36864 45056 61440 53248 4096 4096 4096)
  8847.         offset: 0@-7).!
  8848. showForms
  8849.     "NoteBarGlyph initialize; showForms"
  8850.  
  8851.     | f |
  8852.     f _ Form extent: 250@40.
  8853.     (BitBlt 
  8854.         destForm: f
  8855.         sourceForm: nil
  8856.         halftoneForm: (Form black)
  8857.         combinationRule: (Form over)
  8858.         destOrigin: (0@20)
  8859.         sourceOrigin: (0@0)
  8860.         extent: (250@1)
  8861.         clipRect: f computeBoundingBox) copyBits.
  8862.     (Forms at: #normal) displayOn: f at: 10@20 rule: (Form under).
  8863.     (Forms at: #sharp) displayOn: f at: 50@20 rule: (Form under).
  8864.     (Forms at: #dSharp) displayOn: f at: 90@20 rule: (Form under).
  8865.     (Forms at: #flat) displayOn: f at: 130@20 rule: (Form under).
  8866.     (Forms at: #dFlat) displayOn: f at: 170@20 rule: (Form under).
  8867.     (Forms at: #natural) displayOn: f at: 210@20 rule: (Form under).
  8868.     f edit.! !
  8869.  
  8870. !NoteBarGlyph class methodsFor: 'classification'!
  8871. glyphCategory
  8872.  
  8873.     ^'Music'! !
  8874.  
  8875. !NoteBarGlyph class methodsFor: 'constraint release'!
  8876. releaseConstraints
  8877.  
  8878.     AddC _ nil.
  8879.     CurrentPlan _ nil.
  8880.     MouseConstraints _ nil.
  8881.     OffsetC _ nil.! !
  8882.  
  8883. !PointGlyph class methodsFor: 'classification'!
  8884. glyphCategory
  8885.  
  8886.     ^'Geometric'! !
  8887.  
  8888. !FakeMouseGlyph class methodsFor: 'class initialization'!
  8889. initialize
  8890.     "FakeMouseGlyph initialize"
  8891.  
  8892.     MouseForm _ Form
  8893.                 extent: 16 @ 16
  8894.                 fromArray: #(1 3 7 15 31 63 127 31 31 25 48 48 96 96 192 192 )
  8895.                 offset: -16 @ 0.! !
  8896.  
  8897. !AnchorGlyph class methodsFor: 'classification'!
  8898. glyphCategory
  8899.  
  8900.     ^'Springs'! !
  8901.  
  8902. !SIGGRAPHAnchorGlyph class methodsFor: 'class initialization'!
  8903. initialize
  8904.     "SIGGRAPHAnchorGlyph initialize."
  8905.  
  8906.     AnchorForm _ Form
  8907.             extent: 18 @ 19
  8908.             fromArray: #(480 0 1008 0 1008 0 480 0 192 0 192 0 192 0 192 0 192 0 8385 0 28867 32768 63687 49152 24769 32768 24769 32768 28867 32768 14535 0 7902 0 4092 0 1008 0 )
  8909.             offset: -10 @ -2.! !
  8910.  
  8911. !SIGGRAPHAnchorGlyph class methodsFor: 'classification'!
  8912. glyphCategory
  8913.     ^'SIGGRAPH'! !
  8914.  
  8915. !AnchorGlyph class methodsFor: 'classification'!
  8916. glyphCategory
  8917.  
  8918.     ^'Springs'! !
  8919.  
  8920. !WiringNodeGlyph class methodsFor: 'classification'!
  8921. glyphCategory
  8922.  
  8923.     ^''! !
  8924.  
  8925. !InvisibleWiringNodeGlyph class methodsFor: 'classification'!
  8926. glyphCategory
  8927.  
  8928.     ^''! !
  8929.  
  8930. !InvisiblePointGlyph class methodsFor: 'classification'!
  8931. glyphCategory
  8932.  
  8933.     ^''! !
  8934.  
  8935. !MacDrawDraggerGlyph class methodsFor: 'classification'!
  8936. glyphCategory
  8937.     ^'SIGGRAPH'! !
  8938.  
  8939. !MacDrawDraggerGlyph class methodsFor: 'constraint release'!
  8940. releaseConstraints
  8941.     "MacDrawDraggerGlyph releaseConstraints"
  8942.  
  8943.     CopyConstraint _ nil! !
  8944.  
  8945. !LabeledPointGlyph class methodsFor: 'classification'!
  8946. glyphCategory
  8947.  
  8948.     ^''! !
  8949.  
  8950. !SpringNodeGlyph class methodsFor: 'classification'!
  8951. glyphCategory
  8952.  
  8953.     ^''! !
  8954.  
  8955. !PlanetGlyph class methodsFor: 'class initialization'!
  8956. initialize
  8957.     "PlanetGlyph initialize."
  8958.  
  8959.     DefaultForms _ Array new: 4.
  8960.     DefaultForms at: 1 put: (Form
  8961.             extent: 40 @ 40
  8962.             fromArray: #(0 12288 0 1 56704 0 23 30576 0 93 56796 0 119 30582 0 477 56797 0 887 30583 0 1501 56797 49152 1911 30583 24576 3549 56797 49152 6007 30583 28672 7645 56797 53248 14199 30583 28672 7645 56797 55296 30583 30583 29696 24029 56797 56320 30583 30583 29696 24029 56797 56320 30583 30583 29696 56797 56797 56320 30583 30583 30208 24029 56797 56320 30583 30583 29696 24029 56797 56320 30583 30583 29696 7645 56797 55296 14199 30583 28672 7645 56797 55296 6007 30583 28672 7645 56797 53248 1911 30583 24576 1501 56797 49152 887 30583 0 477 56797 0 119 30582 0 29 56792 0 7 30560 0 1 56704 0 0 4096 0 0 0 0 )
  8963.             offset: 0 @ 0).
  8964.     DefaultForms at: 2 put: (Form
  8965.             extent: 30 @ 30
  8966.             fromArray: #(2 0 21 16384 170 43008 341 21504 682 43520 1365 21760 2730 43648 5461 21824 10922 43680 5461 21824 10922 43680 21845 21840 10922 43680 21845 21840 43690 43688 21845 21840 10922 43680 21845 21840 10922 43680 5461 21824 10922 43680 5461 21824 2730 43648 1365 21760 682 43520 341 21504 170 43008 21 16384 2 0 0 0 )
  8967.             offset: 0 @ 0).
  8968.     DefaultForms at: 3 put: (Form
  8969.             extent: 20 @ 20
  8970.             fromArray: #(64 0 544 0 2184 0 546 0 2184 32768 8738 0 2184 32768 8738 0 2184 32768 8738 8192 2184 32768 8738 0 2184 32768 8738 0 2184 32768 546 0 2184 0 544 0 0 0 0 0 )
  8971.             offset: 0 @ 0).
  8972.     DefaultForms at: 4 put: (Form
  8973.             extent: 30 @ 30
  8974.             fromArray: #(2 0 29 49152 375 29696 477 56320 887 30208 3549 56704 6007 30528 7645 56768 14199 30560 7645 56768 14199 30560 24029 56784 30583 30576 24029 56784 30583 30576 24029 56784 30583 30576 24029 56784 30583 30576 7645 56768 14199 30560 7645 56768 6007 30528 1501 56576 1911 30464 477 56320 375 28672 29 49152 2 0 0 0 )
  8975.             offset: 0 @ 0)! !
  8976.  
  8977. !PlanetGlyph class methodsFor: 'classification'!
  8978. glyphCategory
  8979.     ^'SIGGRAPH'! !
  8980.  
  8981. !TriangleGlyph class methodsFor: 'classification'!
  8982. glyphCategory
  8983.  
  8984.     ^'Geometric'! !
  8985.  
  8986. !StaffLineGlyph class methodsFor: 'classification'!
  8987. glyphCategory
  8988.  
  8989.     ^'Music'! !
  8990.  
  8991. !GrandStaffGlyph class methodsFor: 'constraint release'!
  8992. releaseConstraints
  8993.  
  8994.     WidthC _ nil.! !
  8995.  
  8996. !NoteGlyph class methodsFor: 'class initialization'!
  8997. initialize
  8998.     "NoteGlyph initialize; showForms"
  8999.  
  9000.     Forms _ Dictionary new.
  9001.     Forms at: #normal put: (Form
  9002.         extent: 16@5
  9003.         fromArray: #(62 207 455 486 248)
  9004.         offset: -11@-2).
  9005.     Forms at: #sharp put: (Form
  9006.         extent: 16@17
  9007.         fromArray: #(4096 20480 20480 22528 30720 63488 61440 53310 20687 22983 31206 63736 61440 53248 20480 20480 16384)
  9008.         offset: -8@-9).
  9009.     Forms at: #dSharp put: (Form
  9010.         extent: 16@6
  9011.         fromArray: #(27648 27710 14543 14791 28134 27896 )
  9012.         offset: -8@-3).
  9013.     Forms at: #flat put: (Form
  9014.         extent: 16@13
  9015.         fromArray: #(4096 4096 4096 4096 4096 4096 4096 5632 7742 4815 6087 6630 4344)
  9016.         offset: -9@-10).
  9017.     Forms at: #dFlat put: (Form
  9018.         extent: 16@15
  9019.         fromArray: #(36864 36864 36864 36864 36864 36864 36864 36864 46080 65086 46799 47047 64998 55544 36864)
  9020.         offset: -8@-11).
  9021.     Forms at: #natural put: (Form
  9022.         extent: 16@15
  9023.         fromArray: #(16384 16384 16384 16384 22528 30720 26686 18639 18887 23014 30968 26624 2048 2048 2048)
  9024.         offset: -8@-8).
  9025.  
  9026.     SelectedForms _ Dictionary new.
  9027.     SelectedForms at: #normal put: (Form
  9028.         extent: 16@5
  9029.         fromArray: #(62 255 511 510 248)
  9030.         offset: -11@-2).
  9031.     SelectedForms at: #sharp put: (Form
  9032.         extent: 16@17
  9033.         fromArray: #(4096 20480 20480 22528 30720 63488 61440 53310 20735 23039 31230 63736 61440 53248 20480 20480 16384)
  9034.         offset: -8@-9).
  9035.     SelectedForms at: #dSharp put: (Form
  9036.         extent: 16@6
  9037.         fromArray: #(27648 27710 14591 14847 28158 27896)
  9038.         offset: -8@-3).
  9039.     SelectedForms at: #flat put: (Form
  9040.         extent: 16@13
  9041.         fromArray: #(4096 4096 4096 4096 4096 4096 4096 5632 7742 4863 6143 6654 4344)
  9042.         offset: -9@-10).
  9043.     SelectedForms at: #dFlat put: (Form
  9044.         extent: 16@15
  9045.         fromArray: #(36864 36864 36864 36864 36864 36864 36864 36864 46080 65086 46847 47103 65022 55544 36864)
  9046.         offset: -8@-11).
  9047.     SelectedForms at: #natural put: (Form
  9048.         extent: 16@15
  9049.         fromArray: #(16384 16384 16384 16384 22528 30720 26686 18687 18943 23038 30968 26624 2048 2048 2048)
  9050.         offset: -8@-8).!
  9051. showForms
  9052.     "NoteGlyph initialize; showForms"
  9053.  
  9054.     | f |
  9055.     f _ Form extent: 250@40.
  9056.     (BitBlt 
  9057.         destForm: f
  9058.         sourceForm: nil
  9059.         halftoneForm: (Form black)
  9060.         combinationRule: (Form over)
  9061.         destOrigin: (0@20)
  9062.         sourceOrigin: (0@0)
  9063.         extent: (250@1)
  9064.         clipRect: f computeBoundingBox) copyBits.
  9065.     (Forms at: #normal) displayOn: f at: 10@20 rule: (Form under).
  9066.     (Forms at: #sharp) displayOn: f at: 50@20 rule: (Form under).
  9067.     (Forms at: #dSharp) displayOn: f at: 90@20 rule: (Form under).
  9068.     (Forms at: #flat) displayOn: f at: 130@20 rule: (Form under).
  9069.     (Forms at: #dFlat) displayOn: f at: 170@20 rule: (Form under).
  9070.     (Forms at: #natural) displayOn: f at: 210@20 rule: (Form under).
  9071.     f edit.! !
  9072.  
  9073. !NoteGlyph class methodsFor: 'classification'!
  9074. glyphCategory
  9075.  
  9076.     ^'Music'! !
  9077.  
  9078. !NoteGlyph class methodsFor: 'utilities'!
  9079. keyToPitch: key
  9080.     "Convert the number of a white key to a midi pitch."
  9081.  
  9082.     | octave |
  9083.     octave _ key // 7.
  9084.     ^(octave * 12) + (#(0 2 4 5 7 9 11) at: ((key \\ 7) + 1))!
  9085. pitchToKeyAndMod: pitch
  9086.     "Convert a pitch to the number of the nearest white key plus a modifer."
  9087.  
  9088.     | octave class |
  9089.     octave _ pitch // 12.
  9090.     class _ (pitch \\ 12) + 1.
  9091.     ^Array
  9092.         with: ((octave * 7) + (#(0 0 1 2 2 3 3 4 4 5 6 6) at: class))
  9093.         with: (#(normal sharp normal flat normal normal sharp normal sharp normal flat normal) at: class)! !
  9094.  
  9095. !SpringGlyph class methodsFor: 'classification'!
  9096. glyphCategory
  9097.  
  9098.     ^'Springs'! !
  9099.  
  9100. !SpringGlyph class methodsFor: 'constraint release'!
  9101. releaseConstraints
  9102.  
  9103.     ForceC _ nil.! !
  9104.  
  9105. !FormGlyph class methodsFor: 'classification'!
  9106. glyphCategory
  9107.  
  9108.     ^'General'! !
  9109.  
  9110. !IconGlyph class methodsFor: 'classification'!
  9111. glyphCategory
  9112.  
  9113.     ^'General'! !
  9114.  
  9115. !LineGlyph class methodsFor: 'classification'!
  9116. glyphCategory
  9117.  
  9118.     ^'Geometric'! !
  9119.  
  9120. !WireGlyph class methodsFor: 'classification'!
  9121. glyphCategory
  9122.  
  9123.     ^'Electronic'! !
  9124.  
  9125. !PlainLineGlyph class methodsFor: 'classification'!
  9126. glyphCategory
  9127.  
  9128.     ^'Geometric'! !
  9129.  
  9130. !VectorGlyph class methodsFor: 'classification'!
  9131. glyphCategory
  9132.  
  9133.     ^'Springs'! !
  9134.  
  9135. !VectorGlyph class methodsFor: 'constraint release'!
  9136. releaseConstraints
  9137.     "VectorGlyph releaseConstraints"
  9138.  
  9139.     ArrowC _ nil.
  9140.     DirectionC _ nil.! !
  9141.  
  9142. !PlanetVectorGlyph class methodsFor: 'constraint release'!
  9143. releaseConstraints
  9144.     "PlanetVectorGlyph releaseConstraints"
  9145.  
  9146.     ArrowC _ nil! !
  9147.  
  9148. !PlanetVectorGlyph class methodsFor: 'classification'!
  9149. glyphCategory
  9150.     ^'SIGGRAPH'! !
  9151.  
  9152. !BezierGlyph class methodsFor: 'classification'!
  9153. glyphCategory
  9154.  
  9155.     ^'Geometric'! !
  9156.  
  9157. !BasicRectangleGlyph class methodsFor: 'classification'!
  9158. glyphCategory
  9159.  
  9160.     ^''! !
  9161.  
  9162. !RectangleGlyph class methodsFor: 'classification'!
  9163. glyphCategory
  9164.  
  9165.     ^'Geometric'! !
  9166.  
  9167. !RectangleGlyph class methodsFor: 'constraint release'!
  9168. releaseConstraints
  9169.  
  9170.     CenterC _ nil.! !
  9171.  
  9172. !ArrowHeadGlyph class methodsFor: 'class initialization'!
  9173. initialize
  9174.     "Build my table of arrowhead forms."
  9175.     "ArrowHeadGlyph initialize"
  9176.  
  9177.     FormTable _ Dictionary new.
  9178.     FormTable at: 0 put:                            "0 degrees"
  9179.         (Form
  9180.             extent: 7@7
  9181.             fromArray: #(32768 24576 14336 65024 14336 24576 32768)
  9182.             offset: 0@-3).
  9183.     FormTable at: 45 put:                            "45 degrees"
  9184.         (Form
  9185.             extent: 7@7
  9186.             fromArray: #(512 3072 15360 63488 14336 20480 36864)
  9187.             offset: 0@-6).
  9188.     FormTable at: 90 put:                            "90 degrees"
  9189.         (Form
  9190.             extent: 7@7
  9191.             fromArray: #(4096 4096 14336 14336 31744 21504 37376)
  9192.             offset: -3@-6).
  9193.     FormTable at: 135 put:                        "135 degrees"
  9194.         (Form
  9195.             extent: 7@7
  9196.             fromArray: #(32768 24576 30720 15872 14336 5120 4608)
  9197.             offset: -6@-6).
  9198.     FormTable at: 180 put:                        "180 degrees"
  9199.         (Form
  9200.             extent: 7@7
  9201.             fromArray: #(512 3072 14336 65024 14336 3072 512)
  9202.             offset: -6@-3).
  9203.     FormTable at: 225 put:                        "225 degrees"
  9204.         (Form
  9205.             extent: 7@7
  9206.             fromArray: #(4608 5120 14336 15872 30720 24576 32768)
  9207.             offset: -6@0).
  9208.     FormTable at: 270 put:                        "270 degrees"
  9209.         (Form
  9210.             extent: 7@7
  9211.             fromArray: #(37376 21504 31744 14336 14336 4096 4096)
  9212.             offset: -3@0).
  9213.     FormTable at: 315 put:                        "315 degrees"
  9214.         (Form
  9215.             extent: 7@7
  9216.             fromArray: #(36864 20480 14336 63488 15360 3072 512)
  9217.             offset: 0@0).
  9218.     FormTable at: 360 put: (FormTable at: 0).        "360 is same as 0 degrees"! !
  9219.  
  9220. !ArrowHeadGlyph class methodsFor: 'instance creation'!
  9221. at: aPoint vector: vectorPoint
  9222.     "Create a new instance with the given orientation (determined by vectorPoint) and location."
  9223.  
  9224.     ^(super new)
  9225.         vector: vectorPoint;
  9226.         moveTo: aPoint! !
  9227.  
  9228. !ArrowHeadGlyph class methodsFor: 'classification'!
  9229. glyphCategory
  9230.  
  9231.     ^'General'! !
  9232.  
  9233. !CircleGlyph class methodsFor: 'classification'!
  9234. glyphCategory
  9235.  
  9236.     ^'Geometric'! !
  9237.  
  9238. !CapacitorGlyph class methodsFor: 'classification'!
  9239. glyphCategory
  9240.  
  9241.     ^'Electronic'! !
  9242.  
  9243. !ResistorGlyph class methodsFor: 'classification'!
  9244. glyphCategory
  9245.  
  9246.     ^'Electronic'! !
  9247.  
  9248. !ParaLinesGlyph class methodsFor: 'classification'!
  9249. glyphCategory
  9250.  
  9251.     ^'Geometric'! !
  9252.  
  9253. !ParaLinesGlyph class methodsFor: 'constraint release'!
  9254. releaseConstraints
  9255.  
  9256.     DirectionC _ nil.! !
  9257.  
  9258. !AdagioParser class methodsFor: 'class initialization'!
  9259. initialize
  9260.     "This table drives the scanner. The first letter of each attribute is looked up here to decide what to do with the rest of the attribute. In the case of spaces and punctuation, no further scanning is required."
  9261.     "AdagioParser initialize"
  9262.  
  9263.     | table |
  9264.     StopChar _ 255 asCharacter.
  9265.     table _ Array new: 256 withAll: #undefined.        "default entries"
  9266.     table atAll: #(9 32) put: #spacer.                "tab, space"
  9267.     table atAll: #(10 12 13) put: #separator.        "lf, ff, cr"
  9268.     table at: StopChar asciiValue put: #end.            "StopChar"
  9269.     table at: $; asciiValue put: #semicolon.
  9270.     table at: $, asciiValue put: #comma.
  9271.     table at: $* asciiValue put: #xComment.
  9272.     table at: $!! asciiValue put: #xSpecial.
  9273.     table
  9274.         atAll: ($0 asciiValue to: $9 asciiValue)
  9275.         put: #digit.
  9276.     table
  9277.         atAll: (#($a $b $c $d $e $f $g $A $B $C $D $E $F $G)
  9278.                 collect: [: letter | letter asciiValue])
  9279.          put: #xPitch.
  9280.     table
  9281.         atAll: (#($w $h $q $i $s $W $H $Q $I $S)
  9282.                 collect: [: letter | letter asciiValue])
  9283.          put: #xDuration.
  9284.     table
  9285.         atAll: (#($l $L) collect: [: letter | letter asciiValue])
  9286.         put: #xLoudness.
  9287.     table
  9288.         atAll: (#($n $N) collect: [: letter | letter asciiValue])
  9289.         put: #xNextTime.
  9290.     table
  9291.         atAll: (#($p $P) collect: [: letter | letter asciiValue])
  9292.         put: #xAbsPitch.
  9293.     table
  9294.         atAll: (#($r $R) collect: [: letter | letter asciiValue])
  9295.         put: #xRest.
  9296.     table
  9297.         atAll: (#($t $T) collect: [: letter | letter asciiValue])
  9298.         put: #xTime.
  9299.     table
  9300.         atAll: (#($u $U) collect: [: letter | letter asciiValue])
  9301.         put: #xAbsDuration.
  9302.     table
  9303.         atAll: (#($v $V) collect: [: letter | letter asciiValue])
  9304.         put: #xVoice.
  9305.     table
  9306.         atAll: (#($z $Z) collect: [: letter | letter asciiValue])
  9307.         put: #xProgram.
  9308.     AdagioTypeTable _ table.
  9309.     self initializeOtherTables.!
  9310. initializeOtherTables
  9311.  
  9312.     PitchTable _ Dictionary new.
  9313.     PitchTable at: $c put: 0.
  9314.     PitchTable at: $d put: 2.
  9315.     PitchTable at: $e put: 4.
  9316.     PitchTable at: $f put: 5.
  9317.     PitchTable at: $g put: 7.
  9318.     PitchTable at: $a put: 9.
  9319.     PitchTable at: $b put: 11.
  9320.  
  9321.     DynamicsTable _ Dictionary new.
  9322.     DynamicsTable at: #ppp put: 20.
  9323.     DynamicsTable at: #pp put: 26.
  9324.     DynamicsTable at: #p put: 34.
  9325.     DynamicsTable at: #mp put: 44.
  9326.     DynamicsTable at: #mf put: 58.
  9327.     DynamicsTable at: #f put: 75.
  9328.     DynamicsTable at: #ff put: 98.
  9329.     DynamicsTable at: #fff put: 127.
  9330.  
  9331.     DurationsTable _ Dictionary new.
  9332.     DurationsTable at: $w put: 240.0.
  9333.     DurationsTable at: $h put: 120.0.
  9334.     DurationsTable at: $q put: 60.0.
  9335.     DurationsTable at: $i put: 30.0.
  9336.     DurationsTable at: $s put: 15.0.! !
  9337.  
  9338. !AdagioParser class methodsFor: 'parsing'!
  9339. parse: aStream
  9340.  
  9341.     ^(AdagioParser new) parse: aStream!
  9342. parseFile: fileName
  9343.     "Parse the Adagio file of the given name and answer the resulting score."
  9344.  
  9345.     | fileStream score |
  9346.     fileStream _ (FileStream oldFileNamed: fileName) readOnly.
  9347.     score _ (AdagioParser new) parse: fileStream.
  9348.     fileStream close; release.
  9349.     ^score! !
  9350.  
  9351. !ThreeDLine class methodsFor: 'instance creation'!
  9352. new
  9353.  
  9354.     ^self basicNew initialize! !
  9355.  
  9356. !Method class methodsFor: 'instance creation'!
  9357. names: variableNames methodString: methodString
  9358.     "Create a constraint method from the given string, an assignment statement using the given variable names. For example:
  9359.  
  9360.         Method names: #(a b c) methodString: 'a _ b * c'"
  9361.  
  9362.     ^(super new)
  9363.         names: variableNames
  9364.         methodString: methodString! !
  9365.  
  9366. !QuickPrint class methodsFor: 'instance creation'!
  9367. newOn: aForm box: aRectangle
  9368.     "Create an instance to print on the given form in the given rectangle using the default font."
  9369.  
  9370.     ^(super new)
  9371.         newOn: aForm
  9372.         box: aRectangle
  9373.         font: (TextStyle default fontAt: 1)!
  9374. newOn: aForm box: aRectangle font: aStrikeFont
  9375.     "Create an instance to print on the given form in the given rectangle using the given font."
  9376.  
  9377.     ^(super new) newOn: aForm box: aRectangle font: aStrikeFont! !
  9378.  
  9379. !QuickPrint class methodsFor: 'queries'!
  9380. heightInFont: aStrikeFont
  9381.     "Answer the height of the given font."
  9382.  
  9383.     ^aStrikeFont height!
  9384. width: aString inFont: aStrikeFont
  9385.     "Answer the width of the printed representation of the given string in pixels, assuming we use the default style."
  9386.  
  9387.     | scanner |
  9388.     scanner _ QuickPrint
  9389.         newOn: Display
  9390.         box: (0@0 corner: 0@0)
  9391.         font: aStrikeFont.
  9392.     ^scanner stringWidth: aString! !
  9393.  
  9394. !QuickPrint class methodsFor: 'examples'!
  9395. example1
  9396.     "This will quickly print all the numbers from 1 to 100 on the display and then answer the width of the string 'hello world'."
  9397.     "QuickPrint example1"
  9398.  
  9399.     | scanner |
  9400.     scanner _ QuickPrint
  9401.         newOn: Display
  9402.         box: (20@70 corner: 80@90).
  9403.     1 to: 100 do: [: i | scanner drawString: i printString].
  9404.     ^QuickPrint width: 'hello world' inFont: (TextStyle default fontAt: 1)!
  9405. example2
  9406.     "This will quickly print the string 'hello world' in a number of styles."
  9407.     "QuickPrint example2"
  9408.  
  9409.     | scanner style font |
  9410.     scanner _ QuickPrint
  9411.         newOn: Display
  9412.         box: (10@10 corner: Display boundingBox bottomRight).
  9413.     TextStyle styles do:
  9414.         [: styleName |
  9415.          (styleName = #default) ifTrue:
  9416.             [scanner _ QuickPrint
  9417.                 newOn: Display
  9418.                 box: (180@10 corner: Display boundingBox bottomRight)].
  9419.          (styleName = #large) ifTrue:
  9420.             [scanner _ QuickPrint
  9421.                 newOn: Display
  9422.                 box: (385@10 corner: Display boundingBox bottomRight)].
  9423.          style _ TextStyle styleNamed: styleName.
  9424.          1 to: style fontArray size do:
  9425.              [: i |
  9426.              font _ style fontAt: i.
  9427.              scanner setFont: font.
  9428.               scanner drawString: styleName asString, '-', i printString, ' Hello, world!!'.
  9429.               scanner downBy: font height]].! !
  9430.  
  9431. PitchRider class comment:
  9432. 'PitchRider - IVL PitchRider 400 Control
  9433.  
  9434. This class allows Smalltalk programs to control an IVL PitchRider 400 pitch-to-midi interface (ROM version 2.1).'!
  9435.  
  9436. !PitchRider class methodsFor: 'high level'!
  9437. changeParameter: parameter to: newValue
  9438.     "Attempt to change the given parameter to the given value and verify that it has been changed. This will fail with an error if the parameter is illegal (in which case the PitchRider ignores it) or if there is a communications failure between the computer and the PitchRider. Answers the new parameters string if the operations succeeds."
  9439.  
  9440.     self setParameter: parameter to: newValue.
  9441.     ((self getParameter: parameter) = newValue) ifFalse:
  9442.         [self error: 'Communication failed or illegal value'].
  9443.     ^self report!
  9444. currentParameters
  9445.     "Answer a string describing the current PitchRider parameters."
  9446.  
  9447.     | s p |
  9448.     s _ (String new: 200) writeStream.
  9449.     p _ self getAllParameters.
  9450.     s cr.
  9451.     s nextPutAll: 'Sensitivity: ', (p at: 1) printString; cr.
  9452.     s nextPutAll: 'Reference Pitch (hz): ', (390 + (p at: 2)) printString; cr.
  9453.     s nextPutAll: 'Bottom Octave: ', (p at: 3) printString; cr.
  9454.     s nextPutAll: 'Response Time: ', (p at: 4) printString; cr.
  9455.     s nextPutAll: 'Midi Channel: ', (p at: 5) printString; cr.
  9456.     s nextPutAll: 'Pitchbend Range (semitones): ', (p at: 6) printString; cr.
  9457.     s nextPutAll: 'Volume/Dynamics: ', (p at: 7) printString; cr.
  9458.     s nextPutAll: 'Transpose By (semitones): ', (-12 + (p at: 8)) printString; cr.
  9459.     ^s contents!
  9460. report
  9461.     "Report the current parameters in the Transcript."
  9462.  
  9463.     Transcript show: self currentParameters!
  9464. setup
  9465.     "Set up the PitchRider as I like it."
  9466.  
  9467.     PitchRider changeParameter: 0 to: 1.
  9468.     PitchRider changeParameter: 1 to: 50.
  9469.     PitchRider changeParameter: 2 to: 2.
  9470.     PitchRider changeParameter: 3 to: 2.
  9471.     PitchRider changeParameter: 4 to: 1.
  9472.     PitchRider changeParameter: 5 to: 0.
  9473.     PitchRider changeParameter: 6 to: 5.
  9474.     PitchRider changeParameter: 7 to: 12.! !
  9475.  
  9476. !PitchRider class methodsFor: 'low level - input'!
  9477. getAllParameters
  9478.     "Answer an array of 13 bytes representing the current settings of all PitchRider parameters."
  9479.  
  9480.     | reply |
  9481.     Midi flushInput.
  9482.     self sendDumpRequest.
  9483.     reply _ self getReply: 28.
  9484.     ^reply copyFrom: 14 to: 26!
  9485. getParameter: parameter
  9486.     "Fetch the given parameter from the PitchRider."
  9487.  
  9488.     | reply |
  9489.     Midi flushInput.
  9490.     self sendGetParameter: parameter.
  9491.     reply _ self getReply: 17.
  9492.     ^reply at: 15!
  9493. getReply: size
  9494.     "Answer an the Array representing the PitchRider's reply to the last request. The given number of bytes will be collected."
  9495.  
  9496.     | reply receiveCount startTime c checksum |
  9497.     (size < 15) ifTrue:
  9498.         [self error: 'Minimum message size is 15 bytes'].
  9499.     reply _ Array new: size.
  9500.     receiveCount _ 0.
  9501.     startTime _ Time millisecondClockValue.
  9502.     [receiveCount < size] whileTrue:
  9503.         [((Time millisecondClockValue - startTime) > 10000) ifTrue:
  9504.             [self error: 'Reply is not complete after 10 seconds'].
  9505.          c _ Midi getByte.
  9506.           ((c ~= #NoInput) & (c ~= 254)) ifTrue:
  9507.             [receiveCount _ receiveCount + 1.
  9508.              reply at: receiveCount put: c]].
  9509.     (reply copyFrom: 1 to: 7) with: #(240 0 0 11 0 0 0) do:
  9510.         [: actual : expected |
  9511.          (actual ~~ expected) ifTrue:
  9512.             [self error: 'Bad message header']].
  9513.     ((reply at: size) = 247 "end system exclusive") ifFalse:
  9514.         [self error: 'Incomplete message'].
  9515.     checksum _ self checkSum: reply from: 1 to: 8.
  9516.     ((reply at: 9) ~= checksum) ifTrue:
  9517.         [self error: 'Header Checksum Error'].
  9518.     checksum _ self checkSum: reply from: 10 to: (size - 2).
  9519.     ((reply at: size - 1) ~= checksum) ifTrue:
  9520.         [self error: 'Data Checksum Error'].
  9521.  
  9522.     ^reply! !
  9523.  
  9524. !PitchRider class methodsFor: 'low level - output'!
  9525. checkSum: aByteArray from: start to: stop
  9526.     "Compute the seven-bit checksum of the given subsequence of the given ByteArray."
  9527.  
  9528.     | sum |
  9529.     sum _ 0.
  9530.     start to: stop do:
  9531.         [: i | sum _ sum + (aByteArray at: i)].
  9532.     ^sum bitAnd: 127!
  9533. sendDumpRequest
  9534.     "Request a parameter dump."
  9535.  
  9536.     | request |
  9537.     request _ ByteArray new: 15.
  9538.     request at: 1 put: 240.
  9539.     request at: 2 put: 0.
  9540.     request at: 3 put: 0.
  9541.     request at: 4 put: 11.
  9542.     request at: 5 put: 0.
  9543.     request at: 6 put: 0.
  9544.     request at: 7 put: 0.
  9545.     request at: 8 put: 3.
  9546.     request at: 9 put: (self checkSum: request from: 1 to: 8).
  9547.     request at: 10 put: 2.
  9548.     request at: 11 put: 0.
  9549.     request at: 12 put: 0.
  9550.     request at: 13 put: 0.
  9551.     request at: 14 put: (self checkSum: request from: 10 to: 13).
  9552.     request at: 15 put: 247.
  9553.     request do: [: byte | Midi putByte: byte].!
  9554. sendGetParameter: param
  9555.     "Request a single parameter."
  9556.  
  9557.     | paramByte request |
  9558.     paramByte _ param bitAnd: 127.
  9559.     request _ ByteArray new: 16.
  9560.     request at: 1 put: 240.
  9561.     request at: 2 put: 0.
  9562.     request at: 3 put: 0.
  9563.     request at: 4 put: 11.
  9564.     request at: 5 put: 0.
  9565.     request at: 6 put: 0.
  9566.     request at: 7 put: 0.
  9567.     request at: 8 put: 1.
  9568.     request at: 9 put: (self checkSum: request from: 1 to: 8).
  9569.     request at: 10 put: 3.
  9570.     request at: 11 put: 0.
  9571.     request at: 12 put: 0.
  9572.     request at: 13 put: 0.
  9573.     request at: 14 put: paramByte.    "parameter to get, 0-11"
  9574.     request at: 15 put: (self checkSum: request from: 10 to: 14).
  9575.     request at: 16 put: 247.
  9576.     request do: [: byte | Midi putByte: byte].!
  9577. setParameter: parameter to: aValue
  9578.     "Attempt to set the given parameter to the given value."
  9579.  
  9580.     | parameterByte valueByte request |
  9581.     parameterByte _ parameter bitAnd: 127.
  9582.     valueByte _ aValue bitAnd: 127.
  9583.     "header"
  9584.     request _ ByteArray new: 17.
  9585.     request at: 1 put: 240.
  9586.     request at: 2 put: 0.
  9587.     request at: 3 put: 0.
  9588.     request at: 4 put: 11.
  9589.     request at: 5 put: 0.
  9590.     request at: 6 put: 0.
  9591.     request at: 7 put: 0.
  9592.     request at: 8 put: 0.
  9593.     request at: 9 put: (self checkSum: request from: 1 to: 8).
  9594.     "message"
  9595.     request at: 10 put: 4.
  9596.     request at: 11 put: 0.
  9597.     request at: 12 put: 0.
  9598.     request at: 13 put: 0.
  9599.     request at: 14 put: parameterByte.
  9600.     request at: 15 put: valueByte.
  9601.     request at: 16 put: (self checkSum: request from: 10 to: 15).
  9602.     request at: 17 put: 247.
  9603.     request do: [: byte | Midi putByte: byte].! !
  9604.  
  9605. !Plan class methodsFor: 'instance creation'!
  9606. new
  9607.  
  9608.     ^(self basicNew) initialize! !
  9609.  
  9610. !AbstractConstraint class methodsFor: 'utilities'!
  9611. getVarAt: aPath in: anObject
  9612.     "Fetch the DBVariable object at the given path in the given object. If aPath is nil, then simply return the given object."
  9613.     "NOTE: A path consists of a sequence of unary message selectors separted by period characters. For example, #line1.p2.x refers the DBVariable object found by first sending the message 'line1' to the source object, then sending the message 'p1' to the result of that, and finally sending the 'x' message to the result of that."
  9614.  
  9615.     | next buffer |
  9616.     (aPath isNil) ifTrue: [^anObject].
  9617.     buffer _ WriteStream on: (String new: 16).
  9618.     next _ anObject.
  9619.     aPath do:
  9620.         [: char |
  9621.          (char == $.)
  9622.             ifTrue: 
  9623.                 [next _ next perform: (buffer contents asSymbol).
  9624.                  buffer reset]
  9625.             ifFalse:
  9626.                 [buffer nextPut: char]].
  9627.     (buffer position > 0) ifTrue:
  9628.         [next _ next perform: (buffer contents asSymbol)].
  9629.     ^next! !
  9630.  
  9631. !TwoInOneWayConstraint class methodsFor: 'instance creation'!
  9632. var: inVar1 var: inVar2 var: outVar strength: strengthSymbol
  9633.  
  9634.     ^(super new) var: inVar1 var: inVar2 var: outVar strength: strengthSymbol! !
  9635.  
  9636. !Constraint class methodsFor: 'instance creation'!
  9637. names: variableNames methods: methodStrings
  9638.     "Create a new constraint from the given method strings. The expressions in methodStrings are compiled to produce the actual method bodies for the constraint. For example, the following builds a plus constraint:
  9639.  
  9640.     Constraint
  9641.         names: #(sum a b)
  9642.         methods: #('sum _ a + b'    'a _ sum - b'    'b _ sum - a')
  9643.  
  9644. The constraint thus created may be bound to actual variables with a specific strength (see Constraint>bind:strength:)."
  9645.  
  9646.     | methodList |
  9647.     methodList _ methodStrings collect:
  9648.         [: s | Method names: variableNames methodString: s].
  9649.     ^(super new: variableNames size) methods: methodList! !
  9650.  
  9651. !ScaleConstraint class methodsFor: 'instance creation'!
  9652. var: src var: scale var: offset var: dst strength: strengthSymbol
  9653.     "Create a scale with the given strength on the given variables."
  9654.  
  9655.     ^(self new) src: src scale: scale offset: offset dst: dst strength: strengthSymbol! !
  9656.  
  9657. !OffsetConstraint class methodsFor: 'instance creation'!
  9658. from: variable1 to: variable2 require: aNumber
  9659.     "Install a required OffsetConstraint for the given spacing between the given variables."
  9660.  
  9661.     ^(self new)
  9662.         from: variable1
  9663.         to: variable2
  9664.         strength: #required
  9665.         offset: aNumber!
  9666. from: variable1 to: variable2 strength: strengthSymbol offset: aNumber
  9667.     "Install a required OffsetConstraint with the given strength and spacing between the given variables. For example:
  9668.  
  9669.     OffsetConstraint
  9670.         from: point1 x
  9671.         to: point2 x
  9672.         strength: #preferred
  9673.         offset: 25."
  9674.  
  9675.     ^(self new)
  9676.         from: variable1
  9677.         to: variable2
  9678.         strength: strengthSymbol
  9679.         offset: aNumber!
  9680. fromPoint: p1 to: p2 require: offsetPoint
  9681.     "Install required OffsetConstraints for the given spacing between the given points (both x and y)."
  9682.  
  9683.     self from: p1 xVar to: p2 xVar require: offsetPoint x.
  9684.     self from: p1 yVar to: p2 yVar require: offsetPoint y.! !
  9685.  
  9686. !EqualityConstraint class methodsFor: 'instance creation'!
  9687. var: variable1 var: variable2 strength: strengthSymbol
  9688.     "Create a constraint with the given strength equating the given variables. For example:
  9689.  
  9690.     EqualityConstraint
  9691.         var: line p1 y
  9692.         var: line p2 y
  9693.         strength: #required."
  9694.  
  9695.     ^(self new) var: variable1 var: variable2 strength: strengthSymbol! !
  9696.  
  9697. !LayoutConstraint class methodsFor: 'instance creation'!
  9698. hAlign: p1 with: p2
  9699.     "Add a preferred constraint to equate the y components of the given points."
  9700.  
  9701.     ^self hAlign: p1 with: p2 strength: #preferred!
  9702. hAlign: p1 with: p2 strength: strengthSymbol
  9703.     "Add a constraint with the given strength to equate the y components of the given points."
  9704.  
  9705.     | alignC |
  9706.     alignC _ (self new) bind: (Array with: p1 yVar with: p2 yVar) strength: strengthSymbol.
  9707.     (Planner couldMakeCycle: alignC) ifFalse: [alignC addConstraint].
  9708.     ^alignC!
  9709. vAlign: p1 with: p2
  9710.     "Add a preferred constraint to equate the x components of the given points."
  9711.  
  9712.     ^self vAlign: p1 with: p2 strength: #preferred!
  9713. vAlign: p1 with: p2 strength: strengthSymbol
  9714.     "Add a constraint with the given strength to equate the x components of the given points."
  9715.  
  9716.     | alignC |
  9717.     alignC _ (self new) bind: (Array with: p1 xVar with: p2 xVar) strength: strengthSymbol.
  9718.     (Planner couldMakeCycle: alignC) ifFalse: [alignC addConstraint].
  9719.     ^alignC! !
  9720.  
  9721. !MergeConstraint class methodsFor: 'merging'!
  9722. merge: newVar with: clusterVar strength: strengthSymbol
  9723.     "Merge newVar into the merge cluster containing clusterVar."
  9724.     "Details: To avoid strange topologies possibly leading to cycles, we locate a free end of the merge cluster and merge newVar with that variable. This ensures that merging creates acyclic structures. There is a known problem when a member of a merge is deleted: this may break the merge chain causing things to become unmerged. It could be fixed in the delete operation but for now we choose to live with the problem. The user can always re-merge after a deletion..."
  9725.  
  9726.     | connectionVar |
  9727.     connectionVar _ self variableToMergeWith: newVar in: clusterVar.
  9728.     (connectionVar == nil) ifFalse:
  9729.         [self var: connectionVar var: newVar strength: strengthSymbol].!
  9730. variableToMergeWith: newVar in: clusterVar
  9731.     "Answer a variable from the given merge cluster that the given new variable will merged with. This variable will be be at one end of the merge constraint chain (i.e. will have no determining constraint or no using constraint). If newVar is already part of the merge cluster, then answer nil."
  9732.  
  9733.     | connectionVar mark todo v |
  9734.     (clusterVar class == FreeVariable) ifTrue: [^clusterVar].
  9735.     connectionVar _ nil.
  9736.     mark _ Planner newMark.
  9737.     todo _ OrderedCollection with: clusterVar.
  9738.     [todo isEmpty] whileFalse:
  9739.         [v _ todo removeFirst.
  9740.          (v mark = mark) ifFalse:
  9741.              [(v == newVar)
  9742.                 ifTrue: [^nil]
  9743.                 ifFalse:
  9744.                     [(v determinedBy == nil) ifTrue:
  9745.                         [connectionVar _ v].
  9746.                      v constraints do:
  9747.                         [: c |
  9748.                          ((c isSatisfied) & (c isMergeConstraint)) ifTrue:
  9749.                             [c inputsDo: [: in | todo addLast: in].
  9750.                              todo addLast: c output]]].
  9751.              v mark: mark]].
  9752.     ^connectionVar! !
  9753.  
  9754. !XMouseConstraint class methodsFor: 'instance creation'!
  9755. var: aVariable strength: strengthSymbol offset: aNumber
  9756.     "Create an XMouse constraint on the given variable. The offset is added to the raw mouse position. For example:
  9757.  
  9758.     XMouseConstraint
  9759.         var: myPoint x
  9760.         strength: #preferred
  9761.         offset: (Sensor cursorPoint x)."
  9762.  
  9763.     ^(self new) var: aVariable strength: strengthSymbol offset: aNumber! !
  9764.  
  9765. !EditConstraint class methodsFor: 'instance creation'!
  9766. var: aVariable strength: strengthSymbol
  9767.     "Create an edit constraint with the given strength on the given variable. For example:
  9768.  
  9769.     EditConstraint
  9770.         var: myVar
  9771.         strength: #preferred."
  9772.  
  9773.     ^(self new) var: aVariable strength: strengthSymbol! !
  9774.  
  9775. !StayConstraint class methodsFor: 'instance creation'!
  9776. var: aVariable strength: strengthSymbol
  9777.     "Create and install a new stay constraint with the given strength on the given variable."
  9778.  
  9779.     ^(self new) var: aVariable strength: strengthSymbol! !
  9780.  
  9781. !YMouseConstraint class methodsFor: 'instance creation'!
  9782. var: aVariable strength: strengthSymbol offset: yOffset
  9783.     "Create a YMouse constraint on the given variable. The offset is added to the raw mouse position. For example:
  9784.  
  9785.     YMouseConstraint
  9786.         var: myPoint y
  9787.         strength: #preferred
  9788.         offset: (Sensor cursorPoint y)."
  9789.  
  9790.     ^(self new) var: aVariable strength: strengthSymbol offset: yOffset! !
  9791.  
  9792. !MergeSorter class methodsFor: 'instance creation'!
  9793. new
  9794.  
  9795.     ^(super new) reset! !
  9796.  
  9797. !Strength class methodsFor: 'class initialization'!
  9798. initialize
  9799.     "Initialize the symbolic strength table. Fix the internally caches values of all existing instances."
  9800.     "Strength initialize"
  9801.  
  9802.     StrengthTable _ Dictionary new.
  9803.     StrengthTable at: #absoluteStrongest put: -1000.
  9804.     StrengthTable at: #required put: 0.
  9805.     StrengthTable at: #strongPreferred put: 1.
  9806.     StrengthTable at: #preferred put: 2.
  9807.     StrengthTable at: #strongDefault put: 3.
  9808.     StrengthTable at: #default put: 4.
  9809.     StrengthTable at: #weakDefault put: 5.
  9810.     StrengthTable at: #absoluteWeakest put: 1000.
  9811.  
  9812.     StrengthConstants _ Dictionary new.
  9813.     StrengthTable keys do:
  9814.         [: strengthSymbol |
  9815.             StrengthConstants
  9816.                 at: strengthSymbol
  9817.                 put: ((super new) initializeWith: strengthSymbol)].
  9818.  
  9819.     "Fix arithmetic values stored in all instances."
  9820.     Strength allInstancesDo:
  9821.         [: strength | strength resetValue].
  9822.  
  9823.     AbsoluteStrongest _ Strength of: #absoluteStrongest.
  9824.     AbsoluteWeakest _ Strength of: #absoluteWeakest.
  9825.     Required _ Strength of: #required.! !
  9826.  
  9827. !Strength class methodsFor: 'instance creation'!
  9828. of: aSymbol
  9829.     "Answer an instance with the specified strength."
  9830.  
  9831.     ^StrengthConstants at: aSymbol! !
  9832.  
  9833. !Strength class methodsFor: 'constants'!
  9834. absoluteStrongest
  9835.  
  9836.     ^AbsoluteStrongest!
  9837. absoluteWeakest
  9838.  
  9839.     ^AbsoluteWeakest!
  9840. required
  9841.  
  9842.     ^Required! !
  9843.  
  9844. !PaletteButton class methodsFor: 'instance creation'!
  9845. form: aForm position: aPoint
  9846.  
  9847.     ^(super new) form: aForm position: aPoint! !
  9848.  
  9849. !SpringNodeCluster class methodsFor: 'instance creation'!
  9850. new
  9851.  
  9852.     ^self basicNew initialize! !
  9853.  
  9854. !TracedCollection class methodsFor: 'instance creation'!
  9855. contentsClass: contentsClass
  9856.  
  9857.     ^(self basicNew) contentsClass: contentsClass!
  9858. new
  9859.  
  9860.     ^(self basicNew) contentsClass: IdentitySet! !
  9861.  
  9862. !Score class methodsFor: 'instance creation'!
  9863. fromFile: fileName
  9864.     "Answer the score respresented in Adagio in the file with the given name."
  9865.  
  9866.     | file score |
  9867.     file _ (FileStream oldFileNamed: fileName) readOnly.
  9868.     score _ AdagioParser parse: file.
  9869.     file close; release.
  9870.     ^score!
  9871. new
  9872.     "Answer a new, empty score."
  9873.  
  9874.     ^super new!
  9875. new: initialSize
  9876.     "Answer a new, empty score with room for initialSize elements before growth is needed."
  9877.  
  9878.     ^super new: initialSize! !
  9879.  
  9880. !Score class methodsFor: 'examples'!
  9881. example
  9882.     "Score example"
  9883.  
  9884.     | score startTime currTime |
  9885.     score _ Score new.
  9886.     score add: (NoteElement new: 60 at: 0 dur: 40).
  9887.     score add: (NoteElement new: 62 at: 50 dur: 40).
  9888.     score add: (NoteElement new: 64 at: 100 dur: 40).
  9889.     score add: (NoteElement new: 65 at: 150 dur: 40).
  9890.     score add: (NoteElement new: 67 at: 200 dur: 15).
  9891.     score add: (NoteElement new: 65 at: 225 dur: 25).
  9892.     score add: (NoteElement new: 64 at: 250 dur: 15).
  9893.     score add: (NoteElement new: 62 at: 275 dur: 20).
  9894.     score add: (NoteElement new: 60 at: 300 dur: 100).
  9895.  
  9896.     score prepareToPlay.
  9897.     startTime _ Time millisecondClockValue.
  9898.     [score done] whileFalse:
  9899.         [currTime _ (Time millisecondClockValue - startTime) // 10.
  9900.          score playThrough: currTime].
  9901.     score stopPlaying.! !
  9902.  
  9903. !Symbol class methodsFor: 'instance creation'!
  9904. correctMessage: unknown
  9905.     "Attempt to correct the spelling of an unknown message symbol."
  9906.  
  9907.     | lc hasColon nArgs candidates smaller larger score orderedCandidates labels choice |
  9908.     lc _ unknown first asLowercase.
  9909.     hasColon _ unknown last = $:.
  9910.     unknown first isLetter ifFalse: [^ nil].
  9911.     nArgs _ (unknown select: [:char | char = $:]) size.
  9912.     candidates _ OrderedCollection new.
  9913.     smaller _ unknown size-4.
  9914.     larger _ unknown size+4.
  9915.     Symbol allInstancesDo:  "fast tests first"
  9916.         [:each | ((((each at: 1) = lc
  9917.                 and: [each size between: smaller and: larger])
  9918.                 and: [(each last = $:) = hasColon
  9919.                 and: [each numArgs = nArgs]])
  9920.                 and: [(score _ (each spellAgainst: unknown)) > 50])
  9921.             ifTrue: [candidates add: (Array with: each with: score)]].
  9922.  
  9923.     orderedCandidates _
  9924.         (candidates asSortedCollection: [: i : j | (i at: 2) >= (j at: 2)])
  9925.             collect: [: eachPair | eachPair at: 1].
  9926.  
  9927.     orderedCandidates isEmpty ifTrue: [^ false].
  9928.     labels _ 'abort'.
  9929.     orderedCandidates do: [:each | labels _ labels, '\', each asString].
  9930.     labels _ labels withCRs.
  9931.  
  9932.     choice _ (PopUpMenu labels: labels lines: #(1))
  9933.         startUpWithHeadingAndWaitForSelection: 'Correct to:'.
  9934.  
  9935.     choice <= 1
  9936.         ifTrue: [^ false]
  9937.         ifFalse: [^ orderedCandidates at: (choice - 1)].!
  9938. oldCorrectMessage: unknown
  9939.     "Attempt to correct the spelling of an unknown message symbol."
  9940.  
  9941.     | lc candidates score bestScore guess hasColon nArgs smaller larger |
  9942.     lc _ unknown first asLowercase.
  9943.     hasColon _ unknown last = $:.
  9944.     unknown first isLetter ifFalse: [^ nil].
  9945.     nArgs _ (unknown select: [:char | char = $:]) size.
  9946.     candidates _ OrderedCollection new.
  9947.     smaller _ unknown size-4.
  9948.     larger _ unknown size+4.
  9949.     Symbol allInstancesDo:  "fast tests first"
  9950.         [:each | (((each at: 1) = lc
  9951.                 and: [each size between: smaller and: larger])
  9952.                 and: [(each last = $:) = hasColon and: [each numArgs = nArgs]])
  9953.             ifTrue: [candidates add: each]].
  9954.  
  9955.     bestScore _ 0.
  9956.     candidates do:
  9957.         [:each |
  9958.         (score _ each spellAgainst: unknown) > bestScore ifTrue:
  9959.             [bestScore _ score. guess _ each]].
  9960.  
  9961.     bestScore > 50 ifFalse: [^false].
  9962.     (self confirm: 'Confirm correction to ' , guess)
  9963.         ifTrue: [^ guess asSymbol]
  9964.         ifFalse: [^ nil]! !
  9965.  
  9966. !MusicEventQueue class methodsFor: 'instance creation'!
  9967. new
  9968.     "Answer a new instance of me."
  9969.  
  9970.     ^self new: 10!
  9971. new: aNumber
  9972.     "Answer a new instance with the given initial size."
  9973.  
  9974.     ^self basicNew initialize: aNumber! !
  9975.  
  9976. !FreeVariable class methodsFor: 'instance creation'!
  9977. new
  9978.  
  9979.     ^super new initialize!
  9980. value: aValue
  9981.  
  9982.     ^(super new) initialize; value: aValue! !
  9983.  
  9984. !Form class methodsFor: 'instance creation'!
  9985. readFormFileFromMacPaint: fileName 
  9986.     "Answer an instance of me with bitmap initialized from a MacPaint     
  9987.        file..."
  9988.     "(Form readFormFileFromMacPaint: 'form.paint') edit"
  9989.  
  9990.     "The first 512 bytes of the file are the header. The first four bytes
  9991.     comprise the version number, followed by 38*8 = 304 bytes of       
  9992.     patterns.  The remaining 204 bytes of the header are reserved for
  9993.     future expansion. If the version number is zero, the patterns are     
  9994.     ignored. Hence, programs that wish to create files to be read into
  9995.     MACpaint can just write out 512 bytes of zero as the header.       
  9996.             
  9997.     Following the header are 720 compressed scanlines of data which
  9998.     form the 576 wide by 720 tall bitmap. The bitmap is compressed as 
  9999.     follows:      
  10000.         Any run of three or more equal bytes is compressed into a count       
  10001.         byte and a single data byte. Runs of unequal bytes are passed
  10002.         on literally, preceded also by a count byte, i.e.:      
  10003.             
  10004.         <count byte> <data byte>         count = -1..-127 --> replicate byte 2..128 times       
  10005.         <count byte> <n data bytes>     count =  0.. 127 --> copy 1..128 bytes  
  10006.          uncompressed                        count = -128 ignored for backward compatibility."
  10007.  
  10008.     | file form formBits countByte dataByte byteIndex wordIndex loopIndex |
  10009.     file _ FileStream oldFileNamed: fileName.
  10010.     file binary; readOnly.
  10011.     form _ self new.
  10012.     "Throw away the MacPaint header..."
  10013.     loopIndex _ 1.
  10014.     [loopIndex <= 512]
  10015.         whileTrue: 
  10016.             [dataByte _ file next.
  10017.             loopIndex _ loopIndex + 1].
  10018.     "MacPaint images, by definition, are always  4608 pixels (576 bytes) 
  10019.     wide and 720 rasters tall... so the form will have a word array  
  10020.     that is of size 576 * 720 / 16."
  10021.     form extent: 576 @ 720.
  10022.     formBits _ WordArray new: 25920.
  10023.     wordIndex _ 1.
  10024.     byteIndex _ 1.
  10025.     "And now unpack the file..."
  10026.     [wordIndex < formBits size]
  10027.         whileTrue: 
  10028.             [countByte _ file next.
  10029.             "Compare against 128, because the data as read in is unsigned..."
  10030.             countByte < 128
  10031.                 ifTrue: 
  10032.                     "Uncompressed run..."
  10033.                     [countByte _ countByte + 1.
  10034.                     loopIndex _ 1.
  10035.                     [loopIndex <= countByte]
  10036.                         whileTrue: 
  10037.                             [loopIndex _ loopIndex + 1.
  10038.                             dataByte _ file next.
  10039.                             (byteIndex bitAnd: 1)
  10040.                                 = 1
  10041.                                 ifTrue: [formBits at: wordIndex put: (dataByte bitShift: 8)]
  10042.                                 ifFalse: 
  10043.                                     [formBits at: wordIndex put: (formBits at: wordIndex)
  10044.                                             + dataByte.
  10045.                                     wordIndex _ wordIndex + 1].
  10046.                             byteIndex _ byteIndex + 1]]
  10047.                 ifFalse: 
  10048.                     "Compressed run..."
  10049.                     [dataByte _ file next.
  10050.                     countByte _ 257 - countByte.
  10051.                     loopIndex _ 1.
  10052.                     [loopIndex <= countByte]
  10053.                         whileTrue: 
  10054.                             [loopIndex _ loopIndex + 1.
  10055.                             (byteIndex bitAnd: 1)
  10056.                                 = 1
  10057.                                 ifTrue: [formBits at: wordIndex put: (dataByte bitShift: 8)]
  10058.                                 ifFalse: 
  10059.                                     [formBits at: wordIndex put: (formBits at: wordIndex)
  10060.                                             + dataByte.
  10061.                                     wordIndex _ wordIndex + 1].
  10062.                             byteIndex _ byteIndex + 1]]].
  10063.     form bits: formBits.
  10064.     file close.
  10065.     ^form! !
  10066.  
  10067. !SceneView class methodsFor: 'instance creation'!
  10068. open
  10069.     "SceneView open"
  10070.  
  10071.     self
  10072.         openWithSubview: (self new initialize model: Scene new)
  10073.         label: 'ThingLab II'
  10074.         keepControl: false.!
  10075. openNoTerminateOn: aScene
  10076.     "SceneView open"
  10077.  
  10078.     self
  10079.         openWithSubview: (self new initialize model: aScene)
  10080.         label: 'ThingLab II'
  10081.         keepControl: true.!
  10082. openOn: aScene
  10083.     "SceneView open"
  10084.  
  10085.     self
  10086.         openWithSubview: (self new initialize model: aScene)
  10087.         label: 'ThingLab II'
  10088.         keepControl: false.!
  10089. openWithSubview: aView label: labelString keepControl: keepControl
  10090.     "Open a StandardSystemView with the given label and the given view as a subview."
  10091.  
  10092.     | topView |
  10093.     topView _ SpecialSystemView
  10094.         model: nil
  10095.         label: labelString
  10096.         minimumSize: 60@60.
  10097.     topView
  10098.         borderWidth: 1;
  10099.         addSubView: aView.
  10100.     keepControl
  10101.         ifTrue: [topView controller openNoTerminate]
  10102.         ifFalse: [topView controller open].! !
  10103.  
  10104. !PianoRollView class methodsFor: 'class initialization'!
  10105. initialize
  10106.     "PianoRollView initialize"
  10107.  
  10108.     BarHeight _ 3.
  10109.     VOffset _ (BarHeight * 97).
  10110.     BlackKeyPitches _ OrderedCollection new.
  10111.     #(24 36 48 60 72 84) do:
  10112.         [: octaveC |
  10113.          #(1 3 6 8 10) do:
  10114.             [: blackKey |
  10115.              BlackKeyPitches add: (octaveC + blackKey)]].
  10116.     BlackKeyPitches _ BlackKeyPitches asArray.! !
  10117.  
  10118. !PianoRollView class methodsFor: 'instance creation'!
  10119. openOn: aScore
  10120.     "Create and schedule a view of aScore."
  10121.     "PianoRollView openOn: (Score new)"
  10122.  
  10123.     self new openOn: aScore.! !
  10124.  
  10125. !DemoComments class methodsFor: 'instance creation'!
  10126. from: aClass 
  10127.     | topView holder view |
  10128.     topView _ SpecialSystemView
  10129.                 model: nil
  10130.                 label: 'Demonstration Information'
  10131.                 minimumSize: aClass infoSize.
  10132.     holder _ StringHolder new initialize.
  10133.     holder contents: aClass comment.
  10134.     view _ StringHolderView container: holder.
  10135.     topView borderWidth: 1; addSubView: view.
  10136.     topView controller open! !
  10137.  
  10138. !CWParser class methodsFor: 'parsing'!
  10139. parseFile: fileName
  10140.     "Parse the ConcertWare file of the given name and answer the resulting score."
  10141.  
  10142.     | fileStream score |
  10143.     fileStream _ (FileStream oldFileNamed: fileName) readOnly; binary.
  10144.     score _ (CWParser new) parse: fileStream.
  10145.     fileStream close; release.
  10146.     ^score! !
  10147.  
  10148. !CustomMenu class methodsFor: 'instance creation'!
  10149. new
  10150.  
  10151.     ^(super new) initialize! !
  10152.  
  10153. !CustomMenu class methodsFor: 'example'!
  10154. example
  10155.     "CustomMenu example"
  10156.  
  10157.     | menu |
  10158.     menu _ CustomMenu new.
  10159.     menu add: 'apples' action: #apples.
  10160.     menu add: 'oranges' action: #oranges.
  10161.     menu add: 'peaches' action: #peaches.
  10162.     menu add: 'pears' action: #pears.
  10163.     ^menu invoke: #peaches! !
  10164.  
  10165. !Planner class methodsFor: 'class initialization'!
  10166. initialize
  10167.     "Planner initialize"
  10168.  
  10169.     currentMark _ 1.! !
  10170.  
  10171. !Planner class methodsFor: 'add/remove'!
  10172. incrementalAdd: c
  10173.     "Attempt to satisfy the given constraint and, if successful, incrementally update the dataflow graph."
  10174.     "Details: If satifying the constraint is successful, it may override a weaker constraint on its output. The algorithm attempts to resatisfy that constraint using some other method. This process is repeated until either a) it reaches a variable that was not previously determined by any constraint or b) it reaches a constraint that is too weak to be satisfied using any of its methods. The variables of constraints that have been processed are marked with a unique mark value so that we know where we've been. This allows the algorithm to avoid getting into an infinite loop even if the constraint graph has an inadvertent cycle."
  10175.  
  10176.     | mark overridden |
  10177.     mark _ self newMark.
  10178.     overridden _ c satisfy: mark.
  10179.     [overridden == nil] whileFalse:
  10180.         [overridden _ overridden satisfy: mark].!
  10181. incrementalRemove: c
  10182.     "Entry point for retracting a constraint. Remove the given constraint and incrementally update the dataflow graph."
  10183.     "Details: Retracting the given constraint may allow some currently unsatisfiable downstream constraint be satisfied. We thus collect a list of unsatisfied downstream constraints and attempt to satisfy each one in turn. This list is sorted by constraint strength, strongest first, as a heuristic for avoiding unnecessarily adding and then overriding weak constraints."
  10184.     "Assume: c is satisfied."
  10185.  
  10186.     | out unsatisfied |
  10187.     out _ c output.
  10188.     c removeFromGraph.
  10189.     unsatisfied _ self removePropagate: out.
  10190.     unsatisfied do: [: u | self incrementalAdd: u].! !
  10191.  
  10192. !Planner class methodsFor: 'planning/value propagation'!
  10193. extractPlanFromInputConstraints: inputConstraints
  10194.     "Extract a plan for resatisfaction starting from the outputs of the given seed constraints, usually a set of input constraints."
  10195.     "Details: Collects the satisfied elements of seedConstraints and passes the buck."
  10196.  
  10197.     | seedConstraints |
  10198.     seedConstraints _ OrderedCollection new: 1000.
  10199.     inputConstraints do:
  10200.         [: c | (c isSatisfied) ifTrue: [seedConstraints add: c]].
  10201.     ^self makePlan: seedConstraints!
  10202. extractPlanFromVariables: variables
  10203.     "Extract a plan from the dataflow graph having the given variables. It is assumed that the given set of variables is complete, or at least that it contains all the input and all the history variables of interest."
  10204.     "Details: Simply collects satisfied constraints from the given variables and passes the buck."
  10205.  
  10206.     | seedConstraints |
  10207.     seedConstraints _ OrderedCollection new: 1000.
  10208.     variables do:
  10209.         [: v |
  10210.          (v constraints) do:
  10211.             [: c | (c isSatisfied) ifTrue: [seedConstraints add: c]]].
  10212.     ^self makePlan: seedConstraints!
  10213. makePlan: seedConstraints
  10214.     "Extract a plan for resatisfaction starting from the given seed constraints, usually a set of input constraints. This method assumes that stay optimization is desired; the plan will contain only constraints whose output variables are not stay. Constraints that do no computation, such as stay and edit constraints, are not included in the plan."
  10215.     "Details: The outputs of a constraint are marked when it is added to the plan under construction. A constraint may be appended to the plan when all its input variables are known. A variable is known if either a) the variable is marked (indicating that has been computed by a constraint appearing earlier in the plan), b) the variable is 'stay' (i.e. it is a constant at plan execution time), or c) the variable is not determined by any constraint. The last provision is for past states of history variables, which are not stay but which are also not computed by any constraint."
  10216.     "Assume: seedConstraints are all satisfied."
  10217.  
  10218.     | todo mark plan hotC out inC |
  10219.     todo _ seedConstraints.
  10220.     mark _ self newMark.
  10221.     plan _ Plan new.
  10222.     (todo isEmpty) ifFalse: [hotC _ todo removeFirst].
  10223.     [hotC == nil] whileFalse:
  10224.         [((hotC output mark ~= mark) and:        "not in plan already and..."
  10225.           [hotC inputsKnown: mark])            "eligible for inclusion"
  10226.             ifTrue:
  10227.                 [
  10228. hotC output stay ifFalse: [
  10229.                 plan append: hotC.
  10230. ].
  10231.                  out _ hotC output.
  10232.                  out mark: mark.
  10233.                  hotC _ self nextConstraintIn: todo downstreamOf: out]
  10234.             ifFalse:
  10235.                 [(hotC output mark ~= mark) ifTrue:
  10236.                     ["this code backs up in the constraint graph; this is useful when not all the source nodes are easily determined"
  10237.                      hotC inputsDo:
  10238.                         [: inVar |
  10239.                          inC _ inVar determinedBy.
  10240.                          ((inVar stay) or:
  10241.                           [(inC == nil) or:
  10242.                           [inVar mark == mark]]) ifFalse:
  10243.                             [todo addFirst: inC]]].
  10244.                  hotC _ (todo isEmpty)
  10245.                     ifTrue: [nil]
  10246.                     ifFalse: [todo removeFirst]]].
  10247.     ^plan finalize!
  10248. propagateFrom: aVariable
  10249.     "The given variable has changed. Propagate new values downstream."
  10250.  
  10251.     | todo c |
  10252.     todo _ OrderedCollection new: 1000.
  10253.     c _ self nextConstraintIn: todo downstreamOf: aVariable.
  10254.     [c == nil] whileFalse:
  10255.         [c execute.
  10256.          c _ self nextConstraintIn: todo downstreamOf: c output].! !
  10257.  
  10258. !Planner class methodsFor: 'testing'!
  10259. buildTree: n protoConstraint: protoC
  10260.     "Answer the root of a tree of constraints like the given prototype n deep. Recursive."
  10261.  
  10262.     | tree leftSubtree rightSubtree | 
  10263.     (n <= 0)
  10264.         ifTrue:
  10265.             [tree _ ConstrainedVariable new.
  10266.              tree defaultStay]
  10267.         ifFalse:
  10268.             [tree _ ConstrainedVariable new.
  10269.              leftSubtree _ self buildTree: n - 1 protoConstraint: protoC.
  10270.              rightSubtree _ self buildTree: n - 1 protoConstraint: protoC.
  10271.              (protoC copy) var: tree var: leftSubtree var: rightSubtree strength: #required].
  10272.     ^tree!
  10273. chainTest: n
  10274.     "Do chain-of-equality-constraints performance tests, printing the results in the Transcript."
  10275.     "Planner chainTest: 200"
  10276.  
  10277.     | equalsC vars constraints v1 v2 eqC editConstraint plan |
  10278.     "This constraint is slower than the special-purpose EqualityConstraint."
  10279.     equalsC _ Constraint
  10280.         names: #(a b)
  10281.         methods: #('a _ b'   'b _ a').
  10282.  
  10283.     self report: 'Built chain of ', n printString, ' equality constraints in' times: 1 run:
  10284.         [vars _ (0 to: n) collect: [: i | FreeVariable new].
  10285.          constraints _ OrderedCollection new: n.
  10286.          "thread a chain of equality constraints through the variables"
  10287.          1 to: n do:
  10288.             [: i |
  10289.              v1 _ (vars at: i).
  10290.              v2 _ (vars at: i + 1).
  10291.              eqC _ v1 requireEquals: v2 "equalsC copy var: v1 var: v2 strength: #required".
  10292.              constraints add: eqC].
  10293.          vars last strongDefaultStay].
  10294.  
  10295.     self report: 'Add constraint (case 1):' times: 1 run:
  10296.         [editConstraint _ EditConstraint var: (vars first) strength: #preferred].
  10297.     self report: 'Make Plan (case 1)' times: 1 run:
  10298.         [plan _ Planner extractPlanFromInputConstraints: (Array with: editConstraint)].
  10299.     Transcript show: 'Plan length: ', plan size printString, ' constraints'; cr.
  10300.     self report: 'Execute Plan (case 1):' times: 20 run:
  10301.         [plan execute].
  10302.     self report: 'Remove constraint (case 1):' times: 1 run:
  10303.         [editConstraint destroyConstraint].
  10304.     self report: 'Setting first node: (case 1a):' times: 1 run:
  10305.         [(vars first) setValue: 123 strength: #strongPreferred].
  10306.     self report: 'Setting last node: (case 1b):' times: 1 run:
  10307.         [(vars last) setValue: 321 strength: #strongPreferred].
  10308.     Transcript cr.
  10309.  
  10310.     self report: 'Add constraint (case 2):' times: 1 run:
  10311.         [editConstraint _ EditConstraint var: (vars first) strength: #default].
  10312.     self report: 'Make Plan (case 2):' times: 1 run:
  10313.         [plan _ Planner extractPlanFromInputConstraints: (Array with: editConstraint)].
  10314.     Transcript show: 'Plan length: ', plan size printString, ' constraints'; cr.
  10315.     self report: 'Execute Plan (case 2):' times: 20 run:
  10316.         [plan execute].
  10317.     self report: 'Remove constraint (case 2):' times: 1 run:
  10318.         [editConstraint destroyConstraint].
  10319.     self report: 'Setting first node: (case 2a):' times: 1 run:
  10320.         [(vars first) setValue: 1230 strength: #weakDefault].
  10321.     self report: 'Setting last node: (case 2b):' times: 1 run:
  10322.         [(vars last) setValue: 3210 strength: #weakDefault].
  10323.     Transcript cr.
  10324.  
  10325.     constraints do: [: c | c release].
  10326.     vars do: [: v | v release].
  10327.     Transcript cr.!
  10328. dbStats: n
  10329.     "Planner dbStats: 100"
  10330.  
  10331.     | constraints scale offset src dst vars v1 v2 |
  10332.     constraints _ OrderedCollection new: (2 * n).
  10333.     self report: 'Projection test of ', n printString, ' points. Setup:' times: 1 run:
  10334.         [scale _ ConstrainedVariable value: 10.
  10335.          offset _ ConstrainedVariable value: 1000.
  10336.          1 to: n do:
  10337.             [: i |
  10338.              src _ ConstrainedVariable value: i.
  10339.              dst _ ConstrainedVariable value: i.
  10340.              constraints add: (src defaultStay).
  10341.              constraints add:
  10342.                 (ScaleConstraint
  10343.                     var: src var: scale var: offset var: dst
  10344.                     strength: #required)]].
  10345.     self statsFor: scale newValue: 5.
  10346.     constraints do: [: c | c release].
  10347.     constraints _ OrderedCollection new: (2 * n).
  10348.     Transcript cr.
  10349.  
  10350.     self report: 'ChainTest of ', n printString, ' constraints. Setup:' times: 1 run:
  10351.         [vars _ (0 to: n) collect: [: i | FreeVariable new].
  10352.          constraints _ OrderedCollection new: n.
  10353.          1 to: n do:
  10354.             [: i |
  10355.              v1 _ (vars at: i).
  10356.              v2 _ (vars at: i + 1).
  10357.              constraints add: (v1 requireEquals: v2)].
  10358.          vars last strongDefaultStay].
  10359.     self statsFor: (vars first) newValue: 5.
  10360.     constraints do: [: c | c release].
  10361.     vars do: [: v | v release].
  10362.     Transcript cr.!
  10363. projectionTest: n
  10364. "This test constructs a two sets of variables related to each other by a simple linear transformation (scale and offset). The time is measured to change a variable on either side of the mapping and to change the scale and offset factors. Results are printed in the Transcript."
  10365.     "Planner projectionTest: 1000"
  10366.  
  10367.     | projectionC constraints scale offset src dst editConstraint plan memory |
  10368.     projectionC _ Constraint
  10369.         names: #(src scale offset dst)
  10370.         methods: #('dst _ (src * scale) + offset'   'src _ (dst - offset) // scale').
  10371.     constraints _ OrderedCollection new: (2 * n).
  10372.  
  10373.     memory _ Smalltalk coreLeft.
  10374.     self report: 'Projection test for ', n printString, ' points (Smalltalk):' times: 1 run:
  10375.         [scale _ ConstrainedVariable value: 10.
  10376.          offset _ ConstrainedVariable value: 1000.
  10377.          1 to: n do:
  10378.             [: i |
  10379.              src _ ConstrainedVariable value: i.
  10380.              dst _ ConstrainedVariable value: i.
  10381.              constraints add: (src defaultStay).
  10382.              constraints add:
  10383.                 ("(projectionC copy)"ScaleConstraint
  10384.                     var: src var: scale var: offset var: dst
  10385.                     strength: #required)]].
  10386.     Transcript show: (memory - Smalltalk coreLeft) printString, ' bytes consumed.'; cr.
  10387.     self reportChange: 'Changing a data point:'
  10388.         var: src newValue: 17.
  10389.     self reportChange: 'Changing a projected point:'
  10390.         var: dst newValue: 1050.
  10391.     self reportChange: 'Changing the scale factor:'
  10392.         var: scale newValue: 5.
  10393.     self reportChange: 'Changing the offset:'
  10394.         var: offset newValue: 2000.
  10395.  
  10396.     constraints do: [: c | c release].
  10397.     Transcript cr.!
  10398. report: string times: count run: aBlock
  10399.     "Report the time required to execute the given block."
  10400.  
  10401.     | time |
  10402.     time _ Time millisecondsToRun: [count timesRepeat: aBlock].
  10403.     (count = 1)
  10404.         ifTrue: [Transcript show: string, ' ', (time // count) printString, ' milliseconds'; cr]
  10405.         ifFalse: [Transcript show: string, ' ', (time asFloat / count) printString, ' milliseconds'; cr].!
  10406. reportChange: title var: aVariable newValue: newValue
  10407.  
  10408.     | editConstraint plan |
  10409.     Transcript show: title; cr.
  10410.     self report: '  Adding Constraint:' times: 1 run:
  10411.         [editConstraint _ EditConstraint var: aVariable strength: #preferred].
  10412.     self report: '  Making Plan' times: 1 run:
  10413.         [plan _ Planner extractPlanFromInputConstraints: (Array with: editConstraint)].
  10414.     Transcript show: '  Plan size: ', plan size printString, ' constraints'; cr.
  10415.     self report: '  Executing Plan:' times: 10 run:
  10416.         [aVariable value: newValue. plan execute].
  10417.     self report: '  Removing Constraint:' times: 1 run:
  10418.         [editConstraint destroyConstraint].!
  10419. statsFor: aVariable newValue: newValue
  10420.  
  10421.     | editConstraint plan |
  10422.     self report: '  Latency:' times: 1 run:
  10423.         [editConstraint _ EditConstraint var: aVariable strength: #preferred.
  10424.          plan _ Planner extractPlanFromInputConstraints: (Array with: editConstraint)].
  10425.     self report: '  ExecutionTime:' times: 100 run:
  10426.         [aVariable value: newValue. plan execute].
  10427.     editConstraint destroyConstraint.!
  10428. treeTest: n
  10429.     "Build an adder tree of depth n and measure the time required to change the root."
  10430.     "Planner treeTest: 5"
  10431.  
  10432.     | plusC tree |
  10433.     plusC _ Constraint
  10434.         names: #(sum a b)
  10435.         methods: #('a _ sum - b'   'b _ sum - a'   'sum _ a + b').
  10436.     self report: 'Built adder tree of depth ', n printString, ' in' times: 1 run:
  10437.         [tree _ self buildTree: n protoConstraint: plusC].
  10438.     self reportChange: 'Changing root of tree' var: tree newValue: 10.! !
  10439.  
  10440. !Planner class methodsFor: 'private'!
  10441. addPropagate: aConstraint mark: mark
  10442.     "Recompute the walkabout strengths and stay flags of all variables downstream of the given constraint and recompute the actual values of all variables whose stay flag is true. If a cycle is detected, remove the given constraint and answer false. Otherwise, answer true."
  10443.     "Details: Cycles are detected when a marked variable is encountered downstream of the given constraint. The sender is assumed to have marked the inputs of the given constraint with the given mark. Thus, encountering a marked node downstream of the output constraint means that there is a path from the constraint's output to one of its inputs."
  10444.     "Note: This method has been hand-optimized for better performance."
  10445.  
  10446.     | nextC oldOutValue cOut constraints determiningC i d todo |
  10447.     nextC _ aConstraint.
  10448.     oldOutValue _ aConstraint output value.
  10449.     [nextC == nil] whileFalse:
  10450.         [cOut _ nextC recalculate.
  10451.          (cOut mark = mark) ifTrue:
  10452.             [aConstraint output value: oldOutValue.
  10453.              self incrementalRemove: aConstraint.
  10454.              ^false].
  10455.          "The remaining code in this block is equivalent to:
  10456.             'nextC _ self nextConstraintIn: todo downstreamOf: v'"
  10457.          nextC _ nil.
  10458.          constraints _ cOut constraints.
  10459.          determiningC _ cOut determinedBy.
  10460.          i _ constraints size.
  10461.          [i > 0] whileTrue:
  10462.             [d _ constraints at: i.
  10463.              ((d == determiningC) not and: [d isSatisfied]) ifTrue:
  10464.                 [(nextC == nil)
  10465.                     ifTrue: [nextC _ d]
  10466.                     ifFalse:
  10467.                         [(todo == nil) ifTrue: [todo _ OrderedCollection new: 100].
  10468.                          todo add: d]].
  10469.               i _ i - 1].
  10470.          ((nextC == nil) and: [(todo ~~ nil) and: [todo size > 0]]) ifTrue:
  10471.             [nextC _ todo removeFirst]].
  10472.     ^true!
  10473. newMark
  10474.     "Select a previously unused mark value."
  10475.     "Details: We just keep incrementing. If necessary, the counter will turn into a LargePositiveInteger. In that case, it will be a bit slower to compute the next mark but the algorithms will all behave correctly. We reserve the value '0' to mean 'unmarked'. Thus, this generator starts at '1' and will never produce '0' as a mark value."
  10476.  
  10477.     ^currentMark _ currentMark + 1!
  10478. nextConstraintIn: todo downstreamOf: aVariable
  10479.  
  10480.     | next constraints determiningC i c |
  10481.     next _ nil.
  10482.     constraints _ aVariable constraints.
  10483.     determiningC _ aVariable determinedBy.
  10484.     i _ constraints size.
  10485.     [i > 0] whileTrue:
  10486.         [c _ constraints at: i.
  10487.          ((c == determiningC) or: [c isSatisfied not]) ifFalse:
  10488.             [(next == nil)
  10489.                 ifTrue: [next _ c]
  10490.                 ifFalse: [todo add: c]].
  10491.          i _ i - 1].
  10492.     ((next == nil) and: [todo size > 0]) ifTrue:
  10493.         [next _ todo removeFirst].
  10494.     ^next!
  10495. removePropagate: aVariable
  10496.     "Update the walkabout strengths and stay flags of all variables downstream of the given constraint. Answer a collection of unsatisfied constraints sorted in order of decreasing strength."
  10497.  
  10498.     | unsatisfied todo v nextC |
  10499.     unsatisfied _ SortedCollection sortBlock: [: c1 : c2 | c1 strength stronger: c2 strength].
  10500.     todo _ OrderedCollection new: 1000.
  10501.     v _ aVariable.
  10502.     v determinedBy: nil.
  10503.     v walkStrength: Strength absoluteWeakest.
  10504.     v stay: true.
  10505.     [true] whileTrue:
  10506.         [v unsatisfiedConstraintsInto: unsatisfied.
  10507.          nextC _ self nextConstraintIn: todo downstreamOf: v.
  10508.          (nextC == nil) ifTrue: [^unsatisfied].
  10509.          v _ nextC recalculate].! !
  10510.  
  10511. !Planner class methodsFor: 'cycle detection'!
  10512. couldMakeCycle: aConstraint
  10513.     "Answer true if adding the given constraint could produce a cycle. SLOW!!!!"
  10514.  
  10515.     | mark |
  10516.     aConstraint possibleMethodsDo:
  10517.         [: inputs : output |
  10518.          mark _ self newMark.
  10519.          self markDownstreamFrom: output mark: mark.
  10520.          inputs do: [: in | (in mark = mark) ifTrue: [^true]]].
  10521.     ^false!
  10522. markDownstreamFrom: aVariable mark: mark
  10523.     "Mark all variables downstream of the given variable with the given mark."
  10524.  
  10525.     | todo v |
  10526.     todo _ OrderedCollection new: 1000.
  10527.     v _ aVariable.
  10528.     [true] whileTrue:
  10529.         [v mark: mark.
  10530.          v constraints do:
  10531.             [: c |
  10532.              c possibleMethodsDo:
  10533.                 [: inputs : output |
  10534.                   ((output mark == mark) or: [output == v]) ifFalse:
  10535.                     [todo add: output]]].
  10536.          (todo isEmpty) ifTrue: [^self].
  10537.          v _ todo removeFirst].! !
  10538.  
  10539. !MidiRecorder class methodsFor: 'class initialization'!
  10540. initialize
  10541.     "MidiRecorder initialize."
  10542.  
  10543.     InitialSize _ 500.
  10544.  
  10545.     "Build the default midi action table. This table is a 255 element array of actions to be performed when a byte whose value is the entries index is received. Note that DefaultMidiTable at: 0 is not defined; however, we never actually use a data byte (< 128) to index into the table."
  10546.  
  10547.     DefaultMidiTable _ Array new: 255 withAll: #badTableEntry:.
  10548.     1 to: 127 do: [: i | DefaultMidiTable at: i put: #data:].
  10549.  
  10550.     128 to: 143 do: [: i | DefaultMidiTable at: i put: #recordTwo:].        "Key off"
  10551.     144 to: 159 do: [: i | DefaultMidiTable at: i put: #recordTwo:].        "Key on"
  10552.     160 to: 175 do: [: i | DefaultMidiTable at: i put: #recordTwo:].        "Key pressure (after-touch)"
  10553.     176 to: 191 do: [: i | DefaultMidiTable at: i put: #recordTwo:].        "Control change"
  10554.     192 to: 207 do: [: i | DefaultMidiTable at: i put: #recordOne:].        "Program change"
  10555.     208 to: 223 do: [: i | DefaultMidiTable at: i put: #recordOne:].        "Channel pressure"
  10556.     224 to: 239 do: [: i | DefaultMidiTable at: i put: #recordTwo:].        "Pitch wheel change"
  10557.  
  10558.     DefaultMidiTable at: 240 put: #recordSysExclusive:.    "Start of system exclusive block"
  10559.     DefaultMidiTable at: 241 put: #undefined:.
  10560.     DefaultMidiTable at: 242 put: #ignoreTwo:.            "Song position select"
  10561.     DefaultMidiTable at: 243 put: #ignoreOne:.            "Song select"
  10562.     DefaultMidiTable at: 244 put: #undefined:.
  10563.     DefaultMidiTable at: 245 put: #undefined:.
  10564.     DefaultMidiTable at: 246 put: #ignore:.                "Tune request"
  10565.     DefaultMidiTable at: 247 put: #endSysExclusive:.    "End of system exclusive block"
  10566.     DefaultMidiTable at: 248 put: #ignore:.                "Timing clock"
  10567.     DefaultMidiTable at: 249 put: #undefined:.
  10568.     DefaultMidiTable at: 250 put: #ignore:.                "Start"
  10569.     DefaultMidiTable at: 251 put: #ignore:.                "Continue"
  10570.     DefaultMidiTable at: 252 put: #ignore:.                "Stop/Clock"
  10571.     DefaultMidiTable at: 253 put: #undefined:.
  10572.     DefaultMidiTable at: 254 put: #ignore:.                "Active sensing"
  10573.     DefaultMidiTable at: 255 put: #ignore:.                "System reset"! !
  10574.  
  10575. !MidiRecorder class methodsFor: 'instance creation'!
  10576. new
  10577.  
  10578.     ^(super new) resetMidiTable; reset; yourself! !
  10579.  
  10580. !ThreeDPoint class methodsFor: 'instance creation'!
  10581. new
  10582.  
  10583.     ^self basicNew initialize!
  10584. x: x y: y z: z
  10585.  
  10586.     ^(self basicNew initialize) x: x y: y z: z! !
  10587.  
  10588. !ClippingRectangle class methodsFor: 'instance creation'!
  10589. from: aRectangle
  10590.  
  10591.     ^(self new)
  10592.         clipOrigin: aRectangle origin corner: aRectangle corner!
  10593. origin: point1 corner: point2
  10594.  
  10595.     ^(self new)
  10596.         clipOrigin: point1 corner: point2!
  10597. origin: point1 extent: extent
  10598.  
  10599.     ^(self new)
  10600.         clipOrigin: point1 corner: (point1 + extent)! !
  10601.  
  10602. !ClippingRectangle class methodsFor: 'example'!
  10603. example1
  10604.     "ClippingRectangle example1"
  10605.  
  10606.     | r ans |
  10607.     r _ ClippingRectangle origin: 0@0 corner: 20@20.
  10608.     ans _ r clipFrom: -5@-5 to: 32@32.
  10609.     ^(ans first)
  10610.         ifFalse: ['REJECTED']
  10611.         ifTrue: [(ans at: 2) printString,
  10612.                 ' -> ', (ans at: 3) printString]!
  10613. example2
  10614.     "ClippingRectangle example2"
  10615.  
  10616.     | r lines ans |
  10617.     r _ ClippingRectangle origin: 0@0 corner: 20@20.
  10618.     lines _ (OrderedCollection new)
  10619.         "these should be accepted and possibly clipped"
  10620.         add: (Array with: 5@5 with: 32@32);
  10621.         add: (Array with: -5@-5 with: 12@12);
  10622.         add: (Array with: 32@32 with: -5@-5);
  10623.         add: (Array with: 5@5 with: 12@12);
  10624.  
  10625.         "these should be rejected"
  10626.         add: (Array with: -5@-5 with: -5@132);
  10627.         add: (Array with: -5@-5 with: -112@-112);
  10628.         add: (Array with: 32@32 with: 70@90);
  10629.         add: (Array with: 32@5 with: 70@5);
  10630.         add: (Array with: -5@5 with: -1@5);
  10631.         add: (Array with: -5@-5 with: -1@12);
  10632.         yourself.
  10633.     ^lines collect: [: l |
  10634.         ans _ r clipFrom: (l at: 1) to: (l at: 2).
  10635.         (l at: 1) printString, ' -> ', (l at: 2) printString, ' ==> ',
  10636.             ((ans first)
  10637.                 ifFalse: ['REJECTED']
  10638.                 ifTrue: [(ans at: 2) printString, ' -> ', (ans at: 3) printString])]! !
  10639.  
  10640. !NoteElement class methodsFor: 'instance creation'!
  10641. new
  10642.     "Creates a new note with default values."
  10643.  
  10644.     ^super new initialize!
  10645. new: pitch at: time dur: duration
  10646.     "Creates a new instance of me with the given pitch starting at the given starting time and lasting for the given duration. Other attributes are given reasonable defaults."
  10647.  
  10648.     ^(self basicNew)
  10649.         vel: 75 pitch: pitch voice: 1;
  10650.         time: time;
  10651.         dur: duration!
  10652. new: pitch at: time dur: duration vel: velocity voice: voice
  10653.     "Creates a new instance of me with the given pitch, velocity, and voice starting at the given starting time and lasting for the given duration."
  10654.  
  10655.     ^(self basicNew)
  10656.         vel: velocity pitch: pitch voice: voice;
  10657.         time: time;
  10658.         dur: duration! !
  10659.  
  10660. !NoteOff class methodsFor: 'instance creation'!
  10661. new
  10662.     "Creates a new NoteOff with default values."
  10663.  
  10664.     ^self new: 60 at: 0 voice: 1!
  10665. new: pitch at: time voice: voice
  10666.     "Creates a new NoteOff with default values."
  10667.  
  10668.     ^(super new) pitch: pitch; time: time; voice: voice! !
  10669.  
  10670. !Scene class methodsFor: 'instance creation'!
  10671. new
  10672.  
  10673.     ^self basicNew initialize! !
  10674.  
  10675. !MarimbaPlayer class methodsFor: 'instance creation'!
  10676. new
  10677.  
  10678.     ^self basicNew initialize!
  10679. open
  10680.     "Open a SceneView on a new instance of me."
  10681.     "MarimbaPlayer open"
  10682.  
  10683.     self new open! !
  10684.  
  10685. !Plus1Demo class methodsFor: 'constraint release'!
  10686. releaseConstraints
  10687.     "Plus1Demo releaseConstraints"
  10688.  
  10689.     PrintConstraint _ PlusConstraint _ nil! !
  10690.  
  10691. !Plus1Demo class methodsFor: 'access'!
  10692. infoSize
  10693.     ^700@250! !
  10694.  
  10695. !CFKDemo class methodsFor: 'access'!
  10696. infoSize
  10697.     ^700@310! !
  10698.  
  10699. !AnchorLine1Demo class methodsFor: 'access'!
  10700. infoSize
  10701.     ^900@270! !
  10702.  
  10703. !MacDrawDemo class methodsFor: 'class initialization'!
  10704. initialize
  10705.     "MacDrawDemo initialize."
  10706.  
  10707.     draggerBoxForm _ Form extent: self dragBox extent.
  10708.     draggerBoxForm white.
  10709.     draggerBoxForm border: draggerBoxForm boundingBox width: 1.
  10710.     draggerBoxForm offset: (MacDrawDemo dragBox width // -2 @ (MacDrawDemo dragBox height // -2)).! !
  10711.  
  10712. !MacDrawDemo class methodsFor: 'layout constants'!
  10713. dashBottom
  10714.     ^self dashTop + 20!
  10715. dashTop
  10716.     ^250!
  10717. dragBottom
  10718.     ^self dashTop - 20!
  10719. dragBox
  10720.     ^0@0 extent: 10@10!
  10721. draggerBoxForm
  10722.     ^draggerBoxForm!
  10723. dragTop
  10724.     ^self dragBottom - 100!
  10725. leftEdge
  10726.     ^50!
  10727. maxDash
  10728.     ^125!
  10729. minDash
  10730.     ^5!
  10731. rightEdge
  10732.     ^550! !
  10733.  
  10734. !MacDrawDemo class methodsFor: 'constraint release'!
  10735. releaseConstraints
  10736.     "MacDrawDemo releaseConstraints"
  10737.  
  10738.     MinLengthConstraint _ MaxLengthConstraint _ MinRightConstraint _ MinRight2Constraint _ DashDragAlignConstraint _ CalculateSpareConstraint _ nil! !
  10739.  
  10740. !MacDrawDemo class methodsFor: 'access'!
  10741. infoSize
  10742.     ^700@330! !
  10743.  
  10744. !SplittingDemo class methodsFor: 'class initialization'!
  10745. initialize
  10746.     "SplittingDemo initialize"
  10747.  
  10748.     RandomStream _ Random new.
  10749.     RandomStream _ Array with: 1 with: 113@210 with: self pathArray!
  10750. pathArray
  10751.     | a |
  10752.     a _ OrderedCollection new.
  10753.     a add: 113 @ 211.
  10754.     a add: 113 @ 212.
  10755.     a add: 113 @ 217.
  10756.     a add: 113 @ 221.
  10757.     a add: 115 @ 225.
  10758.     a add: 115 @ 229.
  10759.     a add: 119 @ 233.
  10760.     a add: 123 @ 233.
  10761.     a add: 127 @ 237.
  10762.     a add: 131 @ 241.
  10763.     a add: 132 @ 241.
  10764.     a add: 133 @ 241.
  10765.     a add: 134 @ 241.
  10766.     a add: 135 @ 241.
  10767.     a add: 139 @ 242.
  10768.     a add: 143 @ 242.
  10769.     a add: 147 @ 242.
  10770.     a add: 151 @ 244.
  10771.     a add: 155 @ 244.
  10772.     a add: 159 @ 244.
  10773.     a add: 163 @ 244.
  10774.     a add: 167 @ 244.
  10775.     a add: 171 @ 244.
  10776.     a add: 175 @ 244.
  10777.     a add: 179 @ 245.
  10778.     a add: 183 @ 245.
  10779.     a add: 187 @ 247.
  10780.     a add: 191 @ 247.
  10781.     a add: 195 @ 249.
  10782.     a add: 197 @ 251.
  10783.     a add: 201 @ 255.
  10784.     a add: 203 @ 259.
  10785.     a add: 207 @ 261.
  10786.     a add: 209 @ 265.
  10787.     a add: 211 @ 269.
  10788.     a add: 213 @ 273.
  10789.     a add: 215 @ 277.
  10790.     a add: 216 @ 281.
  10791.     a add: 216 @ 285.
  10792.     a add: 218 @ 289.
  10793.     a add: 218 @ 293.
  10794.     a add: 218 @ 297.
  10795.     a add: 218 @ 301.
  10796.     a add: 218 @ 305.
  10797.     a add: 216 @ 309.
  10798.     a add: 216 @ 313.
  10799.     a add: 212 @ 317.
  10800.     a add: 212 @ 321.
  10801.     a add: 208 @ 325.
  10802.     a add: 204 @ 329.
  10803.     a add: 200 @ 333.
  10804.     a add: 198 @ 337.
  10805.     a add: 197 @ 338.
  10806.     a add: 196 @ 338.
  10807.     a add: 192 @ 340.
  10808.     a add: 191 @ 340.
  10809.     a add: 187 @ 340.
  10810.     a add: 183 @ 340.
  10811.     a add: 179 @ 340.
  10812.     a add: 175 @ 339.
  10813.     a add: 171 @ 339.
  10814.     a add: 167 @ 339.
  10815.     a add: 163 @ 337.
  10816.     a add: 159 @ 333.
  10817.     a add: 155 @ 331.
  10818.     a add: 151 @ 327.
  10819.     a add: 149 @ 323.
  10820.     a add: 147 @ 319.
  10821.     a add: 145 @ 315.
  10822.     a add: 145 @ 311.
  10823.     a add: 141 @ 307.
  10824.     a add: 139 @ 303.
  10825.     a add: 139 @ 299.
  10826.     a add: 137 @ 295.
  10827.     a add: 135 @ 291.
  10828.     a add: 133 @ 287.
  10829.     a add: 129 @ 283.
  10830.     a add: 125 @ 279.
  10831.     a add: 121 @ 275.
  10832.     a add: 117 @ 275.
  10833.     a add: 113 @ 271.
  10834.     a add: 112 @ 271.
  10835.     a add: 111 @ 271.
  10836.     a add: 107 @ 270.
  10837.     a add: 103 @ 270.
  10838.     a add: 99 @ 270.
  10839.     a add: 95 @ 268.
  10840.     a add: 91 @ 268.
  10841.     a add: 87 @ 268.
  10842.     a add: 83 @ 270.
  10843.     a add: 79 @ 270.
  10844.     a add: 75 @ 270.
  10845.     a add: 71 @ 270.
  10846.     a add: 67 @ 270.
  10847.     a add: 63 @ 270.
  10848.     a add: 59 @ 270.
  10849.     a add: 55 @ 270.
  10850.     a add: 51 @ 266.
  10851.     a add: 47 @ 266.
  10852.     a add: 43 @ 262.
  10853.     a add: 39 @ 260.
  10854.     a add: 35 @ 258.
  10855.     a add: 31 @ 254.
  10856.     a add: 29 @ 250.
  10857.     a add: 29 @ 246.
  10858.     a add: 27 @ 242.
  10859.     a add: 27 @ 238.
  10860.     a add: 27 @ 234.
  10861.     a add: 27 @ 230.
  10862.     a add: 27 @ 226.
  10863.     a add: 26 @ 222.
  10864.     a add: 26 @ 218.
  10865.     a add: 26 @ 214.
  10866.     a add: 26 @ 210.
  10867.     a add: 30 @ 206.
  10868.     a add: 30 @ 202.
  10869.     a add: 31 @ 198.
  10870.     a add: 33 @ 194.
  10871.     a add: 35 @ 190.
  10872.     a add: 37 @ 186.
  10873.     a add: 39 @ 182.
  10874.     a add: 41 @ 180.
  10875.     a add: 45 @ 176.
  10876.     a add: 49 @ 174.
  10877.     a add: 51 @ 172.
  10878.     a add: 55 @ 168.
  10879.     a add: 61 @ 165.
  10880.     a add: 65 @ 162.
  10881.     a add: 71 @ 159.
  10882.     a add: 77 @ 156.
  10883.     a add: 80 @ 150.
  10884.     a add: 86 @ 147.
  10885.     a add: 92 @ 145.
  10886.     a add: 96 @ 145.
  10887.     a add: 102 @ 143.
  10888.     a add: 106 @ 143.
  10889.     a add: 110 @ 143.
  10890.     a add: 116 @ 143.
  10891.     a add: 122 @ 143.
  10892.     a add: 128 @ 143.
  10893.     a add: 132 @ 145.
  10894.     a add: 136 @ 147.
  10895.     a add: 138 @ 151.
  10896.     a add: 142 @ 153.
  10897.     a add: 144 @ 155.
  10898.     a add: 146 @ 159.
  10899.     a add: 148 @ 161.
  10900.     a add: 152 @ 165.
  10901.     a add: 152 @ 169.
  10902.     a add: 156 @ 173.
  10903.     a add: 156 @ 177.
  10904.     a add: 156 @ 181.
  10905.     a add: 154 @ 185.
  10906.     a add: 154 @ 189.
  10907.     a add: 150 @ 193.
  10908.     a add: 148 @ 197.
  10909.     a add: 144 @ 201.
  10910.     a add: 144 @ 205.
  10911.     a add: 140 @ 207.
  10912.     a add: 139 @ 208.
  10913.     a add: 138 @ 208.
  10914.     a add: 137 @ 209.
  10915.     a add: 136 @ 209.
  10916.     a add: 135 @ 210.
  10917.     a add: 134 @ 210.
  10918.     a add: 133 @ 210.
  10919.     a add: 132 @ 211.
  10920.     a add: 131 @ 211.
  10921.     a add: 130 @ 211.
  10922.     a add: 129 @ 211.
  10923.     a add: 128 @ 212.
  10924.     a add: 127 @ 212.
  10925.     a add: 126 @ 212.
  10926.     a add: 125 @ 212.
  10927.     a add: 124 @ 212.
  10928.     a add: 124 @ 211.
  10929.     a add: 123 @ 211.
  10930.     a add: 122 @ 211.
  10931.     a add: 121 @ 210.
  10932.     a add: 120 @ 210.
  10933.     a add: 119 @ 210.
  10934.     a add: 118 @ 210.
  10935.     ^a asArray! !
  10936.  
  10937. !SplittingDemo class methodsFor: 'random numbers'!
  10938. nextRandom
  10939.     | v |
  10940.     v _ (RandomStream next * 20.0) truncated - 4.
  10941.     v > 4 ifTrue: [v _ 0].
  10942.     ^v!
  10943. nextRandomX
  10944.     | i |
  10945.     i _ RandomStream at: 1.
  10946.     i > (RandomStream at: 3) size ifTrue: [i _ RandomStream at: 1 put: 1].
  10947.     RandomStream at: 2 put: ((RandomStream at: 3) at: i).
  10948.     RandomStream at: 1 put: (i + 1).
  10949.     ^(RandomStream at: 2) x!
  10950. nextRandomY
  10951.     ^(RandomStream at: 2) y! !
  10952.  
  10953. !SplittingDemo class methodsFor: 'access'!
  10954. infoSize
  10955.     ^700@280! !
  10956.  
  10957. !ThreePlanetDemo class methodsFor: 'access'!
  10958. infoSize
  10959.     ^600@360! !
  10960.  
  10961. BufferStream comment:
  10962. 'A BufferStream is a re-usable ReadWriteStream. The message resetAll will reset both the readLimit and the current position (making it empty). BufferStream is used by the Adagio parser and for Midi input.'!
  10963.  
  10964. !BufferStream methodsFor: 'special'!
  10965. buffer
  10966.     "Answer my buffer (collection) to allow direct access for high performace I/O. Experts only!!!!"
  10967.  
  10968.     ^collection!
  10969. resetAll
  10970.     "Resets both the read and write positions so that the BufferStream becomes empty and may be re-used."
  10971.  
  10972.     readLimit _ position _ 0.!
  10973. setReadLimit: newLimit
  10974.     "Sets the readLimit to newLimit. No sanity check is performed, so be sure you know what you are doing!!"
  10975.  
  10976.     readLimit _ newLimit!
  10977. throughEnd
  10978.     "Answer a sub-collection containing all the unread characters in the buffer."
  10979.  
  10980.     ^collection copyFrom: position + 1 to: readLimit! !
  10981.  
  10982. Method comment:
  10983. 'I represent a method whose enforement procedure is stored in a Smalltalk block. Users may create custom methods by supplying an assignment expression string and a set of formal constrained variable names. See my instance creation protocol for further details.
  10984.  
  10985. Instance variables:
  10986.     block        block to execute to enforce the constraint <BlockContext>
  10987. '!
  10988.  
  10989. !Method methodsFor: 'initialize-release'!
  10990. names: variableNames methodString: methodString
  10991.     "Initialize a method by compiling the given string considering the given collection of variable names to represent the parameters of the method (i.e. its inputs and outputs). A given variable may not be both an input and an output. Note: Any free variables in the methodString will be considered global (if they appear in 'Smalltalk') or temporary variables. The user is given a warning, however, since such cases are unusual and a free variable may indicate a typographical error."
  10992.  
  10993.     | insOutsTemps ins outs temps |
  10994.     insOutsTemps _ self extractInsOutsAndTemps: methodString using: variableNames.
  10995.     ins _ insOutsTemps at: 1.
  10996.     outs _ insOutsTemps at: 2.
  10997.     temps _ insOutsTemps at: 3.
  10998.     outIndex _ self outIndexForIns: ins outs: outs temps: temps all: variableNames.
  10999.     block _ Compiler
  11000.             evaluate:
  11001.                 ((self blockPrefixForIns: ins temps: temps args: variableNames),
  11002.                  methodString,
  11003.                  (self blockPostfixForOuts: outs allNames: variableNames))
  11004.             for: nil
  11005.             logged: false.
  11006.     (temps size > 0) ifTrue: [block fixTemps].!
  11007. release
  11008.  
  11009.     outIndex _ nil.
  11010.     block _ nil.! !
  11011.  
  11012. !Method methodsFor: 'constraint support'!
  11013. execute: variables
  11014.     "Execute myself to enforce my constraint on the given variables."
  11015.  
  11016.     block value: variables.!
  11017. outIndex
  11018.     "Answer the index of my output in the bindings array."
  11019.  
  11020.     ^outIndex! !
  11021.  
  11022. !Method methodsFor: 'printing'!
  11023. printOn: aStream
  11024.  
  11025.     aStream
  11026.         nextPutAll: 'Method(', self asOop printString;
  11027.         nextPutAll: ' out: ', outIndex printString, ')'.! !
  11028.  
  11029. !Method methodsFor: 'private'!
  11030. blockPostfixForOuts: outNames allNames: allNames
  11031.     "Answer a string to be used as the postfix when creating a block for this method."
  11032.  
  11033.     | stream |
  11034.     "make a stream and add separator to terminate user's method string"
  11035.     stream _ WriteStream on: (String new).
  11036.     stream nextPutAll: '.'; cr.
  11037.  
  11038.     "build the expression postfix, creating assignments for all outputs"
  11039.     1 to: allNames size do:
  11040.         [: index |
  11041.          (outNames includes: (allNames at: index)) ifTrue:
  11042.             [stream tab; nextPutAll: '(vars at: '.
  11043.              stream nextPutAll: index printString, ') value: '.
  11044.              stream nextPutAll: (allNames at: index), '.'; cr]].
  11045.  
  11046.     stream tab; nextPutAll: ']'; cr.
  11047.     ^stream contents!
  11048. blockPrefixForIns: inNames temps: tempNames args: argNames
  11049.     "Answer a string to be used as the prefix when creating a block for a method with the given input names. All constraint variables are declared as temporaries, in addition to the temporary variables from the method string. Input variable temporaries are initialized from the argument vector."
  11050.  
  11051.     | stream |
  11052.     stream _ WriteStream on: (String new).
  11053.  
  11054.     "build the expression prefix, making all the variables look like temps"
  11055.     stream nextPutAll: '| '.
  11056.     argNames do: [: v | stream nextPutAll: v; space].
  11057.     tempNames do: [: v | stream nextPutAll: v; space].
  11058.     stream nextPutAll: '|'; cr.
  11059.  
  11060.     "build the block header and input assignments"
  11061.     stream tab; nextPutAll: '[: vars |'; cr.
  11062.     1 to: argNames size do:
  11063.         [: index |
  11064.          (inNames includes: (argNames at: index)) ifTrue:
  11065.             [stream tab; nextPutAll: (argNames at: index), ' _ (vars at: '.
  11066.             stream nextPutAll: index printString.
  11067.             stream nextPutAll: ') value.'; cr]].
  11068.  
  11069.     stream tab.
  11070.     ^stream contents!
  11071. extractInsOutsAndTemps: methodString using: allNames
  11072.     "Extract the input, output and temporary variable names from the Smalltalk expression represented by the given string. A temporary variable is one that is neither an input, an output, or a global. Answer an array containing the three lists (ins, outs, temps)."
  11073.  
  11074.     | s parseTree ins outs temps |
  11075.     s _ (String new: 200) writeStream.
  11076.     s nextPutAll: 'DoIt'; cr; cr.
  11077.     s tab; nextPutAll: '| '.
  11078.     allNames do: [: vName | s nextPutAll: vName; space].
  11079.     s nextPutAll: '|'; cr; tab; nextPutAll: methodString.
  11080.     parseTree _ self parse: s contents.
  11081.     ins _ parseTree referenced.
  11082.     outs _ parseTree assignedTo.
  11083.     temps _ parseTree allVariables select:
  11084.         [: v | ((allNames includes: v) not) &
  11085.               ((Smalltalk includesKey: v) not)].
  11086.     ^Array with: ins with: outs with: temps!
  11087. outIndexForIns: inNames outs: outNames temps: tempNames all: allNames
  11088.     "Answer the index of the method output in the constraint variables. Raise an error if the input and output arg lists are not disjoint or if there is not exactly one output. Warn the user if the method code has free variables (these will be made into temporaries)."
  11089.  
  11090.     | realOuts |
  11091.     realOuts _ outNames copy removeAll: tempNames; yourself.
  11092.     (realOuts size = 1) ifFalse:
  11093.         [self error: 'Constraints must have exactly one output variable'].
  11094.  
  11095.     outNames do:
  11096.         [: v |
  11097.          ((inNames includes: v) and:
  11098.           [allNames includes: v]) ifTrue:
  11099.             [self error: v asString, ' cannot be both input and output!!']].
  11100.  
  11101.     tempNames do:
  11102.         [: v |
  11103.          Transcript show:
  11104.             'Warning: ''', v, ''' is assumed to be a temporary.'; cr].
  11105.  
  11106.     ^allNames indexOf: (realOuts asOrderedCollection first)!
  11107. parse: methodString
  11108.     "Answer the Smalltalk parse tree for the given string."
  11109.  
  11110.     ^(Compiler new)
  11111.         parse: methodString readStream
  11112.         in: UndefinedObject
  11113.         notifying: nil! !
  11114.  
  11115. !ThreeDtoTwoDLineConstraint methodsFor: 'all'!
  11116. constrainPointFrom: threeDPoint to: twoDPoint
  11117.  
  11118.     | vars |
  11119.     vars _ OrderedCollection new: 20.
  11120.     (type = #x)
  11121.         ifTrue:
  11122.             [vars
  11123.                 add: (twoDPoint xVar);
  11124.                 add: (threeDPoint xVar); add: (threeDPoint zVar);
  11125.                 add: (sinTheta); add: (cosTheta)]
  11126.         ifFalse:
  11127.             [vars
  11128.                 add: (twoDPoint yVar);
  11129.                 add: (threeDPoint xVar); add: (threeDPoint yVar); add: (threeDPoint zVar);
  11130.                 add: (sinTheta); add: (cosTheta); add: (sinPhi); add: (cosPhi)].
  11131.     ^(protoConstraint copy) vars: vars strength: #required!
  11132. constraintFrom: threeDLine to: twoDLine
  11133.  
  11134.     ^(point = #p1)
  11135.         ifTrue: [self constrainPointFrom: threeDLine p1 to: twoDLine p1]
  11136.         ifFalse: [self constrainPointFrom: threeDLine p2 to: twoDLine p2]!
  11137. type: xOrY point: p1orP2 sinTheta: sinThetaVar cosTheta: cosThetaVar sinPhi: sinPhiVar cosPhi: cosPhiVar
  11138.     "Set the type of constraint to either #x or #y."
  11139.  
  11140.     type _ xOrY.
  11141.     point _ p1orP2.
  11142.     (type = #x)
  11143.         ifTrue:
  11144.             [protoConstraint _ Constraint
  11145.                 names: #(x pX pZ sinTheta cosTheta)
  11146.                 methods: #(
  11147.                     'x _ (pX * cosTheta) + (pZ * sinTheta) + 150')]
  11148.         ifFalse:
  11149.             [protoConstraint _ Constraint
  11150.                 names: #(y pX pY pZ sinTheta cosTheta sinPhi cosPhi)
  11151.                 methods: #(
  11152.                     'y _ (pX * sinTheta * sinPhi) + (pY * cosPhi) - (pZ * cosTheta * sinPhi) + 150')].
  11153.     sinTheta _ sinThetaVar.
  11154.     cosTheta _ cosThetaVar.
  11155.     sinPhi _ sinPhiVar.
  11156.     cosPhi _ cosPhiVar.! !
  11157.  
  11158. MergeSorter comment:
  11159. 'I collect a list of ordered sub-sequences which can later be merged into a single, sorted sequence. Objects may be added to the current sub-sequence using ''add:'' or ''addCheck:''. (''addCheck:'' will check the assumption that the sub-sequence is really sorted in ascending order.) A new sub-sequence is started with the message ''startNewSublist''. I was created for use by the Adagio parser by I can also be used to merge scores.
  11160. '!
  11161.  
  11162. !MergeSorter methodsFor: 'initialize-release'!
  11163. reset
  11164.     "Reset to pristine, empty state."
  11165.  
  11166.     lists _ OrderedCollection new: 40.
  11167.     currList _ nil.
  11168.     lastAdded _ nil.
  11169.     self startNewSublist.! !
  11170.  
  11171. !MergeSorter methodsFor: 'accessing'!
  11172. add: anItem
  11173.     "Adds anItem to the current list."
  11174.  
  11175.     currList addLast: anItem.
  11176.     lastAdded _ anItem.!
  11177. addCheck: anItem
  11178.     "Adds anItem to my current list. Checks the assumption that anItem is >= to the last item added."
  11179.  
  11180.     ((lastAdded notNil) and: [anItem < lastAdded])
  11181.         ifTrue: [self error: 'Attempt to add an item out of sequence'].
  11182.     self add: anItem.!
  11183. size
  11184.     "Answer the total count of all items added to me since the last time I was reset."
  11185.  
  11186.     ^(lists inject: 0 into: [:subTotal :next | subTotal + next size]) + currList size!
  11187. startNewSublist
  11188.     "Start a new ordered sublist. Subsequent additions will be appended to this list until the next startNewSublist message is received."
  11189.  
  11190.     ((currList notNil) and: [currList isEmpty not])
  11191.         ifTrue: [lists addLast: currList].
  11192.     currList _ Score new: 1000.
  11193.     lastAdded _ nil.! !
  11194.  
  11195. !MergeSorter methodsFor: 'converting'!
  11196. asClass: aCollectionClass
  11197.     "Answer the merge of all my lists as a sorted sequenceable collection of the given class. Release myself for efficient reclaimation."
  11198.  
  11199.     | list1 list2 result |
  11200.     self startNewSublist.        "Adds currList to list (my list of sorted sublists)."
  11201.     (lists size == 0) ifTrue: [^aCollectionClass new].    "we're empty so return an empty collection"
  11202.     lists _ lists asSortedCollection: [: list1 : list2 | list1 size < list2 size].
  11203.     [lists size > 1]
  11204.         whileTrue:
  11205.             [list1 _ lists removeFirst.
  11206.              list2 _ lists removeFirst.
  11207.              lists add: (self merge: list1 with: list2 as: aCollectionClass)].
  11208.  
  11209.     (lists first species = aCollectionClass)
  11210.         ifTrue: [result _ lists first]
  11211.         ifFalse:
  11212.             [result _ aCollectionClass new: lists first size.
  11213.              result addAll: lists first].
  11214.  
  11215.     "release myself to avoid circular garbage"
  11216.     lists _ currList _ lastAdded _ nil.
  11217.     ^result!
  11218. asScore
  11219.     "Answer the merge of all my lists as a sorted Score and release my storage."
  11220.  
  11221.     ^self asClass: Score!
  11222. merge: list1 with: list2 as: aCollectionClass
  11223.     "Answer with an instance of aCollectionClass containing all the elements of list1 and list2 merged into it in the proper order."
  11224.     "NOTE: assumes list1 and list2 are already sorted in ascending order."
  11225.  
  11226.     | newList pos1 pos2 limit1 limit2 next1 next2 |
  11227.     newList _ aCollectionClass new: (list1 size + list2 size).
  11228.  
  11229.     (list1 isEmpty) ifTrue: [newList addAll: list2. ^newList].
  11230.     (list2 isEmpty) ifTrue: [newList addAll: list1. ^newList].
  11231.  
  11232.     pos1 _ 1.
  11233.     pos2 _ 1.
  11234.     limit1 _ list1 size.
  11235.     limit2 _ list2 size.
  11236.     next1 _ list1 at: pos1.
  11237.     next2 _ list2 at: pos2.
  11238.  
  11239.     "Merge list1 and list2 in ascending order until one of them is exhausted."
  11240.     [(pos1 <= limit1) & ( pos2 <= limit2)] whileTrue: [
  11241.         (next1 <= next2)
  11242.             ifTrue: [
  11243.                 newList addLast: next1.
  11244.                 pos1 _ pos1 + 1.
  11245.                 (pos1 <= limit1) ifTrue: [next1 _ list1 at: pos1]]
  11246.             ifFalse: [
  11247.                 newList addLast: next2.
  11248.                 pos2 _ pos2 + 1.
  11249.                 (pos2 <= limit2) ifTrue: [next2 _ list2 at: pos2]]
  11250.     ].
  11251.  
  11252.     "Unless the two lists are the same size, one list will be exhausted first. One of the following
  11253.     two lines will quickly copy the remaining list into newList."
  11254.     (pos1 <= limit1) ifTrue: [newList addAll: (list1 copyFrom: pos1 to: limit1). ^newList].
  11255.     (pos2 <= limit2) ifTrue: [newList addAll: (list2 copyFrom: pos2 to: limit2). ^newList].
  11256.  
  11257.     ^newList! !
  11258.  
  11259. !PairConstraintHolder methodsFor: 'initialize-release'!
  11260. constraint: aBinaryConstraint fromPath: fromPathSymbol toPath: toPathSymbol otherVars: vars strength: aSymbol
  11261.     "Initialize me with the given prototype constraint, paths, additional variables, and strength symbol."
  11262.  
  11263.     protoConstraint _ aBinaryConstraint.
  11264.     fromPath _ fromPathSymbol.
  11265.     toPath _ toPathSymbol.
  11266.     extraVars _ vars.
  11267.     strengthSymbol _ aSymbol.!
  11268. constraint: aBinaryConstraint fromPath: fromPathSymbol toPath: toPathSymbol strength: aSymbol
  11269.     "Initialize me with the given prototype constraint, paths, and strength symbol."
  11270.  
  11271.     protoConstraint _ aBinaryConstraint.
  11272.     fromPath _ fromPathSymbol.
  11273.     toPath _ toPathSymbol.
  11274.     extraVars _ nil.
  11275.     strengthSymbol _ aSymbol.!
  11276. constraintFrom: object1 to: object2
  11277.     "Answer a an instance of my prototype constraint on the given pair of objects using fromPath and toPath to access the appropriate fields of the two objects."
  11278.  
  11279.     | fromVar toVar |
  11280.     fromVar _ Constraint getVarAt: fromPath in: object1.
  11281.     toVar _ Constraint getVarAt: toPath in: object2.
  11282.     (extraVars isNil)
  11283.         ifTrue:
  11284.             [^(protoConstraint copy)
  11285.                 var: fromVar var: toVar
  11286.                 strength: strengthSymbol]
  11287.         ifFalse:
  11288.             [^(protoConstraint copy)
  11289.                 vars: ((Array with: fromVar with: toVar), extraVars)
  11290.                 strength: strengthSymbol]!
  11291. release
  11292.  
  11293.     protoConstraint _ nil.
  11294.     fromPath _ nil.
  11295.     toPath _ nil.
  11296.     strengthSymbol _ nil.! !
  11297.  
  11298. !SetConstraintTests methodsFor: 'tests'!
  11299. directSetup
  11300.     "Sets up maps using direct constraints."
  11301.  
  11302.     | sets scaleC mapC |
  11303.     sets _ (1 to: 4) collect:
  11304.         [: i | (1 to: 100) collect: [: j | FreeVariable value: i]].
  11305.     scale _ FreeVariable value: 4.
  11306.     offset _ FreeVariable value: 100.
  11307.  
  11308.     (sets at: 1) do: [: v | v strongDefaultStay].
  11309.     scaleC _ Constraint
  11310.         names: #(src dst scale offset)
  11311.         methods: #('dst _ (src * scale) + offset'    'src _ (dst - offset) / scale').
  11312.     (sets at: 1) with: (sets at: 2) do:
  11313.         [: src : dst |
  11314.          (scaleC copy)
  11315.             var: src var: dst var: scale var: offset strength: #required].
  11316.  
  11317.     mapC _ Constraint
  11318.         names: #(src dst)
  11319.         methods: #('dst _ src + 100'    'src _ dst - 100').
  11320.     2 to: 3 do: [: i |
  11321.         (sets at: i) with: (sets at: i + 1) do:
  11322.             [: src : dst |
  11323.              (mapC copy)
  11324.                 var: src var: dst strength: #required]].
  11325.     ^sets!
  11326. fastPointDisplay: n
  11327.     "Display n random points as quickly as BitBlt will go."
  11328.     "SetConstraintTests new fastPointDisplay: 1000"
  11329.  
  11330.     | r f p blt points t |
  11331.     r _ Random new.
  11332.     points _ (1 to: n) collect: [: i | ((r next * 400) truncated)@((r next * 300) truncated)].
  11333.     f _ Form extent: 400@300.
  11334.     p _ (Form extent: 1@1) black.
  11335.     blt _ BitBlt 
  11336.         destForm: f
  11337.         sourceForm: p
  11338.         halftoneForm: nil
  11339.         combinationRule: (Form erase)
  11340.         destOrigin: 0@0
  11341.         sourceOrigin: 0@0
  11342.         extent: (p boundingBox extent)
  11343.         clipRect: (f boundingBox).
  11344.     t _ Time millisecondsToRun: [
  11345.         f black.
  11346.         points do: [: p | blt destOrigin: p; copyBits].
  11347.         f displayOn: Display at: 10@10].
  11348.     Transcript cr; show: n printString, ' points displayed in ', t printString, ' milliseconds'; cr.!
  11349. filterDemo: n
  11350.     "Make a scene with n points mapped to underlying points via scale constraints."
  11351.     "SetConstraintTests new filterDemo: 50"
  11352.  
  11353.     | sourceSet threshold destSet selectC r p otherGlyphs scene |
  11354.     sourceSet _ FreeVariable value: TracedCollection new.
  11355.     threshold _ FreeVariable new.
  11356.     destSet _ FreeVariable value: TracedCollection new.
  11357.     selectC _ SetSelectConstraint var: sourceSet var: threshold var: destSet strength: #required.
  11358.     selectC selectBlock: [: el : thresh | el x > thresh].
  11359.     r _ Random new.
  11360.     n timesRepeat:
  11361.         [p _ (PointGlyph new) moveTo:
  11362.                 (((r next * 160.0) + 40.0)@((r next * 160.0) + 40.0) rounded).
  11363.          sourceSet value add: p].
  11364.  
  11365.     
  11366.     otherGlyphs _ FreeVariable value: TracedCollection new.
  11367.     otherGlyphs value add: ((HSliderGlyph on: threshold)
  11368.         width: 210; minVal: 0; maxVal: 210; value: 0;
  11369.         moveTo: 114@13).
  11370.     scene _ Scene new.
  11371.     SetUnionConstraint var: destSet var: otherGlyphs var: scene glyphsVar strength: #required.
  11372.     SceneView openOn: scene.!
  11373. leftOfTest
  11374.     "Test a simple constraint to make one point stay to the left of another using a history constraint."
  11375.     "SetConstraintTests new leftOfTest"
  11376.  
  11377.     | scene p1 p2 leftOfC p3 p4 |
  11378.     scene _ Scene new.
  11379.     p1 _ PointGlyph new moveTo: 30@30.
  11380.     p2 _ PointGlyph new moveTo: 40@30.
  11381.     p3 _ PointGlyph new moveTo: 50@30.
  11382.     p4 _ PointGlyph new moveTo: 60@30.
  11383.     scene addGlyph: p1; addGlyph: p2.
  11384.     scene addGlyph: p3; addGlyph: p4.
  11385.     leftOfC _ Constraint
  11386.         names: #(leftX oldLeftX rightX oldRightX)
  11387.         methods: #('leftX _ oldLeftX min: rightX' 'rightX _ oldRightX max: leftX').
  11388.     (leftOfC copy) var: p1 xVar var: p1 xVar last var: p2 xVar var: p2 xVar last strength: #required.
  11389.     (leftOfC copy) var: p2 xVar var: p2 xVar last var: p3 xVar var: p3 xVar last strength: #required.
  11390.     (leftOfC copy) var: p3 xVar var: p3 xVar last var: p4 xVar var: p4 xVar last strength: #required.
  11391.     SceneView openOn: scene.!
  11392. mapTests: which
  11393.     "Computes the performance of maintaining pair-wise relationships between two sets using either direct (which = #direct) or virtual (which = #virtual) constraints."
  11394.     "SetConstraintTests new mapTests: #direct"
  11395.     "SetConstraintTests new mapTests: #virtual"
  11396.  
  11397.     | aTime rTime pTime eTime edits plan sets |
  11398.     (which == #direct)
  11399.         ifTrue: [sets _ self directSetup]
  11400.         ifFalse: [sets _ self virtualSetup].
  11401.     aTime _ pTime _eTime _ rTime _ 0.
  11402.     10 timesRepeat: [
  11403.         aTime _ aTime +
  11404.             (Time millisecondsToRun:
  11405.                 [edits _ Array with: (EditConstraint var: scale strength: #default)
  11406.                  "edits _ (1 to: 10) collect:
  11407.                     [: i | EditConstraint var: ((sets at: 4) at: i) strength: #preferred]"]).
  11408.         pTime _ pTime +
  11409.             (Time millisecondsToRun:
  11410.                 [plan _ Planner extractPlanFromInputConstraints: edits]).
  11411.         Transcript show: 'Plan size = ', plan size printString; cr.
  11412.         eTime _ eTime +
  11413.             (Time millisecondsToRun: [plan execute]).
  11414.         plan release.
  11415.         rTime _ rTime +
  11416.             (Time millisecondsToRun: [edits do: [: e | e destroyConstraint]])].
  11417.     ^Array with: aTime / 10.0 with: pTime / 10.0 with: eTime / 10.0 with: rTime / 10.0
  11418.  
  11419. "Results (the envelope, please...)
  11420. Virtual constraints:
  11421. 100 elements, 3 constraints deep, changing 10 items (30 constraints)
  11422.  (102.7 90.1 10.1 288.0 )
  11423.  (105.8 91.0 8.3 277.7 )
  11424.  (102.6 96.3 8.1 275.7 )
  11425.  
  11426. 100 elements, 3 constraints deep, changing scale factor on first map (300 constraints)
  11427.  (579.1 831.2 64.6 1053.8 )
  11428.  (597.5 825.1 63.6 1041.5 )
  11429.  (576.2 819.8 63.8 1035.1 )
  11430.  
  11431. Conventional constraints:
  11432. 100 elements, 3 constraints deep, changing 10 items (30 constraints)
  11433.  (68.6 59.4 11.4 162.0 )
  11434.  (70.7 52.4 7.1 149.7 )
  11435.  (75.0 48.2 8.1 150.6 )
  11436.  
  11437. 100 elements, 3 constraints deep, changing scale factor on first map (300 constraints)
  11438.  (153.5 440.8 71.8 267.9 )
  11439.  (159.5 444.9 69.8 258.6 )
  11440.  (159.9 432.6 71.8 255.4 )
  11441.  (161.1 450.2 80.8 255.1 )
  11442.  
  11443. Complex vs. Simple Plan Extractions:
  11444. complex, scale change:
  11445.  (430.4 546.2 47.07 719.5 ) (416.2 551.5 47.15 729.7 ) (422.1 550.6 45.6 727.9 )
  11446. simple, scale change:
  11447.  (423.6 575.0 61.81 724.2 ) (423.5 575.0 63.03 729.0 ) (422.3 578.2 62.22 726.7 )
  11448. complex, 10 edits:
  11449.  (69.7 76.9 5.43 203.0 ) (74.0 76.8 5.73 196.8 ) (73.7 75.9 5.43 194.9 )
  11450. simple, 10 edits:
  11451.  (73.8 68.6 6.78 195.9 ) (73.9 69.7 7.08 193.7 ) (72.8 65.6 6.56 205.0 )"!
  11452. projectionDemo: n
  11453.     "Make a scene with n points mapped to underlying points via scale constraints."
  11454.     "SetConstraintTests new projectionDemo: 50"
  11455.  
  11456.     | scene xOffset yOffset scaleC r p1 p2 |
  11457.     scene _ Scene new.
  11458.     scale _ FreeVariable value: 1.0.
  11459.     xOffset _ FreeVariable new.
  11460.     yOffset _ FreeVariable new.
  11461.     scaleC _ Constraint
  11462.         names: #(src dst scale offset)
  11463.         methods: #(
  11464.             'dst _ ((src * scale) / 100.0) rounded + offset'
  11465.             'src _ ((dst - offset) asFloat * 100.0 / scale) rounded').
  11466.     r _ Random new.
  11467.     n timesRepeat:
  11468.         [p1 _ PointGlyph new moveTo: ((r next * 200.0) - 100.0)@((r next * 150.0) - 75.0).
  11469.          p1 xVar defaultStay.
  11470.          p1 yVar defaultStay.
  11471.          p2 _ PointGlyph new.
  11472.          (scaleC copy)
  11473.             var: p1 xVar var: p2 xVar
  11474.             var: scale var: xOffset strength: #required.
  11475.          (scaleC copy)
  11476.             var: p1 yVar var: p2 yVar
  11477.             var: scale var: yOffset strength: #required.
  11478.         scene addGlyph: p2].
  11479.  
  11480.     scene addGlyph: ((HSliderGlyph on: xOffset)
  11481.         minVal: 50.0; maxVal: 350.0; value: 200;
  11482.         moveTo: 80@20).
  11483.     scene addGlyph: ((HSliderGlyph on: yOffset)
  11484.         minVal: 50.0; maxVal: 350.0; value: 200;
  11485.         moveTo: 80@35).
  11486.     scene addGlyph: ((HSliderGlyph on: scale)
  11487.         minVal: 1.0; maxVal: 350.0; value: 88.0;
  11488.         moveTo: 230@20).
  11489.     SceneView openOn: scene.!
  11490. virtualSetup
  11491.     "Sets up maps using a virtual constraint."
  11492.  
  11493.     | setVars scaleC v1 v2 mapC |
  11494.     setVars _ (1 to: 4) collect:
  11495.         [: i |
  11496.          FreeVariable value:
  11497.             (TracedCollection contentsClass: OrderedCollection)].
  11498.     scale _ FreeVariable value: 4.
  11499.     offset _ FreeVariable value: 100.
  11500.  
  11501.     scaleC _ Constraint
  11502.         names: #(src dst scale offset)
  11503.         methods: #('dst _ (src * scale) + offset'    'src _ (dst - offset) / scale').
  11504.     1 to: 100 do:
  11505.         [: i |
  11506.          v1 _ FreeVariable value: i.
  11507.          v1 strongDefaultStay.
  11508.          v2 _ FreeVariable value: i.
  11509.          (scaleC copy)
  11510.             var: v1 var: v2 var: scale var: offset strength: #required.
  11511.          (setVars at: 1) value add: v1.
  11512.          (setVars at: 2) value add: v2].
  11513.  
  11514.     2 to: 3 do:
  11515.         [: i |
  11516.          mapC _ (BijectiveMapConstraint new)
  11517.             fromSet: (setVars at: i) toSet: (setVars at: i + 1)
  11518.             fromClass: FreeVariable toClass: FreeVariable
  11519.             strength: #required.
  11520.          mapC offset: nil from: nil by: 100 strength: #required].
  11521.  
  11522.     ^setVars collect: [: setVar | setVar value contents]! !
  11523.  
  11524. !String methodsFor: 'converting'!
  11525. asScore
  11526.     "Answer the Adagio score resulting from parsing me."
  11527.  
  11528.     ^AdagioParser parse: self readStream! !
  11529.  
  11530. Score comment:
  11531. 'I am a subclass of OrderedCollection used to store collections of notes. I know how to perform the score I contain. (Aside: it may be desirable to implement a separate player class to allow a given score to be played as a cannon with itself. If so, the performance technique used here may be copied and extended.)
  11532.  
  11533. My instance variables are:
  11534.     scoreTime        a cache for the total score duration
  11535.     maxDur            a cache of the duration of my longest note
  11536.     noteCount        the total size of this score (used during performance)
  11537.     nextIndex        index of the next note to play during a performance
  11538.     activeNotes        list of active notes (notes that have been struck but not released)
  11539. '!
  11540.  
  11541. !Score methodsFor: 'functions'!
  11542. edit
  11543.     "Open a piano-roll editor on myself."
  11544.  
  11545.     PianoRollView openOn: self.!
  11546. maxDur
  11547.     "Answer the duration of my longest note in centiseconds. This quantity is cached in my maxDur instance variable and only recomputed if maxDur is nil."
  11548.  
  11549.     maxDur isNil
  11550.         ifTrue: [maxDur _ self computeMaxDur].
  11551.     ^maxDur!
  11552. maxVoice
  11553.     "Answer the number of the highest numbered voice in myself."
  11554.  
  11555.     ^self
  11556.         inject: 1
  11557.         into:
  11558.             [: maxVoice : scoreEl |
  11559.              (scoreEl isNote)
  11560.                 ifTrue: [maxVoice max: scoreEl voice]
  11561.                 ifFalse: [maxVoice]]!
  11562. mergedWith: aScore
  11563.     "Answer a new score that consists of all my elements merged with all the elements of aScore."
  11564.  
  11565.     | sorter |
  11566.     sorter _ MergeSorter new.
  11567.     self do: [: note | sorter add: note copy].
  11568.     sorter startNewSublist.
  11569.     aScore do: [: note | sorter add: note copy].
  11570.     ^sorter asScore!
  11571. scoreTime
  11572.     "Answer my total playing time in centiseconds. This quantity is cached in my scoreTime instance variable and only recomputed if scoreTime is nil."
  11573.  
  11574.     scoreTime isNil
  11575.         ifTrue: [scoreTime _ self computeScoreTime].
  11576.     ^scoreTime! !
  11577.  
  11578. !Score methodsFor: 'positioning'!
  11579. findIndexForTime: aTime
  11580.     "Do a binary search to find the first score element with the given time."
  11581.  
  11582.     | index low high |
  11583.     low _ firstIndex.
  11584.     high _ lastIndex.
  11585.     [index _ high + low // 2.
  11586.      low <= high]
  11587.         whileTrue:
  11588.             [((self basicAt: index) time < aTime)
  11589.                 ifTrue: [low _ index + 1]
  11590.                 ifFalse: [high _ index - 1]].
  11591.     ^(low + 1 - firstIndex) min: self size!
  11592. indexAfter: aTime
  11593.     "Answer the index of my first element that is after the given time or the index of my last element is greater than the time of my last element."
  11594.  
  11595.     | index size |
  11596.     index _ self findIndexForTime: aTime.
  11597.     size _ self size.
  11598.     [(index < size) and: [(self at: index) time <= aTime]]
  11599.         whileTrue: [index _ index + 1].
  11600.     ^index!
  11601. indexBefore: aTime
  11602.     "Answer the index of my last element that is at or before the given time or my first index if aTime is less than the time of my first element."
  11603.  
  11604.     | index |
  11605.     index _ self findIndexForTime: aTime.
  11606.     ^((index < self size) and: [(self at: index) time > aTime])
  11607.         ifTrue: [(index - 1) max: 1]
  11608.         ifFalse: [index]! !
  11609.  
  11610. !Score methodsFor: 'performance'!
  11611. done
  11612.     "Answer true if the performance is over."
  11613.  
  11614.     ^(nextIndex > self size) and: [activeNotes isEmpty]!
  11615. play
  11616.     "Play from the beginning at normal speed."
  11617.  
  11618.     self playFrom: 0 rate: 1.!
  11619. playFrom: time rate: theRate
  11620.     "Plays the entire score at the given rate. theRate is 1 for normal speed, 2 for twice speed, 0.75 for three-quarter speed, etc."
  11621.  
  11622.     | rate mSecsAtStart ticks currTime |
  11623.     "Skip to the first note at or after the given time, processing all control changes and program changes along the way to establish the proper synthesizer state."
  11624.     self prepareToPlayFrom: time.
  11625.  
  11626.     rate _ theRate asFloat.
  11627.     mSecsAtStart _ (Time millisecondClockValue) - (10 * time / rate) rounded.
  11628.     [self done | Sensor anyButtonPressed] whileFalse:
  11629.         [ticks _ Time millisecondClockValue - mSecsAtStart.
  11630.          currTime _ ((rate * ticks asFloat) / 10.0) rounded.
  11631.          self playThrough: currTime].
  11632.     self stopPlaying.!
  11633. prepareToPlay
  11634.     "Reset the next note pointer (nextIndex) and the active note list to prepare the score to be played from the beginning."
  11635.  
  11636.     noteCount _ self size.
  11637.     nextIndex _ 1.
  11638.     (activeNotes isNil)
  11639.         ifTrue:
  11640.             [activeNotes _ MusicEventQueue new.
  11641.              activeNotes sortBlock:
  11642.                 [: e1 : e2 | e1 offTime < e2 offTime]]
  11643.         ifFalse: [activeNotes removeAll].!
  11644. prepareToPlayFrom: time
  11645.     "Processes the score up through the given time without playing any notes. All control and program changes are performed to set the state of the synthesizer as if the score had been actually performed."
  11646.  
  11647.     | event |
  11648.     self prepareToPlay.
  11649.     [(nextIndex <= noteCount) and:
  11650.      [(event _ self at: nextIndex) time <= (time - 1)]] whileTrue:
  11651.         [(event isNote) ifFalse: [event turnOff].
  11652.          nextIndex _ nextIndex + 1].!
  11653. stopPlaying
  11654.     "Stop playing and clean up your room!!"
  11655.  
  11656.     Midi allNotesOff.    "turn off all notes in case I was rudely interrupted."
  11657.     nextIndex _ 1.!
  11658. testPlay
  11659.     "Play myself as fast as possible for testing. All midi events are sent but the clock is advanced as quickly as the processing time will allow."
  11660.  
  11661.     | currTime |
  11662.     self prepareToPlay.
  11663.     currTime _ 0.
  11664.     [self done | Sensor anyButtonPressed] whileFalse:
  11665.         [self playThrough: currTime.
  11666.          currTime _ currTime + 10].
  11667.     self stopPlaying.! !
  11668.  
  11669. !Score methodsFor: 'storing'!
  11670. storeAdagioOn: aStream
  11671.     "Write an Adagio representation of myself on the given stream."
  11672.  
  11673.     | maxVoice |
  11674.     aStream nextPutAll: '* Created on ', Time dateAndTimeNow printString.
  11675.     aStream cr; cr.
  11676.     maxVoice _ self maxVoice.
  11677.     1 to: self maxVoice do:
  11678.         [: voice |
  11679.          aStream nextPutAll: '* Voice ', voice printString; cr.
  11680.          aStream nextPutAll: 't0 r u0 v', voice printString; cr.
  11681.          self storeVoice: voice on: aStream.
  11682.          (voice ~~ maxVoice) ifTrue:
  11683.             [aStream cr; cr]].!
  11684. storeAdagioOnFile: aFileName
  11685.     "Write an Adagio representation of myself to a file with the given name."
  11686.     "NOTE: Only the notes of the score are recorded. This could be extended to store control changes or other kinds of score elements but so far that has not been needed."
  11687.  
  11688.     | aStream |
  11689.     aStream _ FileStream newFileNamed: aFileName.
  11690.     aStream nextPutAll: '* ', aFileName; cr.
  11691.     self storeAdagioOn: aStream.
  11692.     aStream close.!
  11693. storeVoice: voice on: aStream
  11694.     "Write an Adagio representation of the given voice to the given stream. To allow nice formatting, the method NoteElement>storeAdagioOn:previous:next: is passed the notes immediately preceding and following the note to be output (which may be nil)."
  11695.  
  11696.     | oldNextIndex previousTone thisTone nextTone |
  11697.     "save nextIndex (used for enumeration) and start voice enumeration"
  11698.     oldNextIndex _ nextIndex.    
  11699.     nextIndex _ 1.
  11700.  
  11701.     "get first three tones"
  11702.     previousTone _ self nextNoteInVoice: voice.
  11703.     thisTone _ self nextNoteInVoice: voice.
  11704.     nextTone _ self nextNoteInVoice: voice.
  11705.  
  11706.     "store first tone, if there is one (the voice could be empty)"
  11707.     (previousTone notNil)
  11708.         ifTrue:
  11709.             [previousTone
  11710.                 storeAdagioOn: aStream
  11711.                 previous:
  11712.                     (NoteElement new: 0 at: 0 dur: 0 vel: 0 voice: voice)
  11713.                 next: thisTone].
  11714.  
  11715.     "store the rest"
  11716.     [thisTone notNil]
  11717.         whileTrue:
  11718.             [thisTone
  11719.                 storeAdagioOn: aStream
  11720.                 previous: previousTone next: nextTone.
  11721.              previousTone _ thisTone.
  11722.              thisTone _ nextTone.
  11723.              nextTone _ self nextNoteInVoice: voice].
  11724.  
  11725.     nextIndex _ oldNextIndex.        "restore nextIndex"! !
  11726.  
  11727. !Score methodsFor: 'private'!
  11728. computeMaxDur
  11729.     "Compute and answer the duration of my longest note in centiseconds."
  11730.  
  11731.     ^self
  11732.         inject: 0
  11733.         into:
  11734.             [: max : scoreEl |
  11735.              ((scoreEl isNote) and: [scoreEl dur > max])
  11736.                 ifTrue: [scoreEl dur]
  11737.                 ifFalse: [max]]!
  11738. computeScoreTime
  11739.     "Compute and answer my total playing time in centiseconds."
  11740.  
  11741.     | endTime noteEnd |
  11742.     endTime _ 0.
  11743.     self do:
  11744.         [: n |
  11745.          (n isNote)
  11746.             ifTrue:
  11747.                 [noteEnd _ n offTime.
  11748.                  (noteEnd > endTime) ifTrue: [endTime _ noteEnd]]
  11749.             ifFalse:
  11750.                 [(n time > endTime) ifTrue: [endTime _ n time]]].
  11751.     ^endTime!
  11752. deepCopy
  11753.  
  11754.     ^self copy!
  11755. nextNoteInVoice: voice
  11756.     "Answer the next note of myself in the given voice at or after nextIndex. Non-note score elements are skipped. Set nextIndex to point to the next scoreElement. Answer nil if the end of the score is reached. Details: This method uses the instance variable nextIndex to maintain state between invocations. The client should set nextIndex to 1 to start the enumeration."
  11757.  
  11758.     | scoreEl |
  11759.     [nextIndex <= self size] whileTrue:
  11760.         [scoreEl _ self at: nextIndex.
  11761.          nextIndex _ nextIndex + 1.
  11762.          ((scoreEl voice == voice) & (scoreEl isNote))
  11763.             ifTrue: [^scoreEl]].
  11764.     ^nil!
  11765. playThrough: time
  11766.     "Play the score up through the given time and answer the time of the next action to be performed (either the next event or the time of the next note to be turned off)."
  11767.  
  11768.     | event nextTime |
  11769.     self turnOffNotesAt: time.
  11770.     [(nextIndex <= noteCount) and:
  11771.      [(event _ self at: nextIndex) time <= time]] whileTrue:
  11772.         [event perform.
  11773.          (event isNote) ifTrue:
  11774.             [activeNotes add: event].
  11775.          nextIndex _ nextIndex + 1].
  11776.  
  11777.     "compute and answer the time of the next activity"
  11778.     (nextIndex <= noteCount)
  11779.         ifTrue:    "not done yet"
  11780.             [nextTime _ (self at: nextIndex) time.
  11781.              (activeNotes isEmpty) ifFalse:
  11782.                 [nextTime _ nextTime min: (activeNotes first offTime)]]
  11783.         ifFalse:    "done playing notes; may have some noteoffs yet"
  11784.             [(activeNotes isEmpty)
  11785.                 ifTrue: [nextTime _ time + 1]
  11786.                 ifFalse: [nextTime _ (activeNotes first offTime)]].
  11787.     ^nextTime max: (time + 1)    "always advance by at least one tick"!
  11788. playThrough: time volume: volume
  11789.     "Play the score up through the given time at the given volume and answer the time of the next action to be performed (either the next event or the time of the next note to be turned off)."
  11790.  
  11791.     | event nextTime |
  11792.     self turnOffNotesAt: time.
  11793.     [(nextIndex <= noteCount) and:
  11794.      [(event _ self at: nextIndex) time <= time]] whileTrue:
  11795.         [(event isNote)
  11796.             ifTrue:
  11797.                 [Midi
  11798.                     noteOn: (event pitch)
  11799.                     vel: (volume min: 127)
  11800.                     chan: (event voice).
  11801.                  activeNotes add: event]
  11802.             ifFalse: [event perform].
  11803.          nextIndex _ nextIndex + 1].
  11804.  
  11805.     "compute and answer the time of the next activity"
  11806.     (nextIndex <= noteCount)
  11807.         ifTrue:    "not done yet"
  11808.             [nextTime _ (self at: nextIndex) time.
  11809.              (activeNotes isEmpty) ifFalse:
  11810.                 [nextTime _ nextTime min: (activeNotes first offTime)]]
  11811.         ifFalse:    "done playing notes; may have some noteoffs yet"
  11812.             [(activeNotes isEmpty)
  11813.                 ifTrue: [nextTime _ time + 1]
  11814.                 ifFalse: [nextTime _ (activeNotes first offTime)]].
  11815.     ^nextTime max: (time + 1)    "always advance by at least one tick"!
  11816. setIndices
  11817.     "Override OrderedCollection's method for this initialization method since we anticipate adding things at the end. (We most frequently use addLast: rather than addFirst: to add to Score objects.)"
  11818.  
  11819.     firstIndex _ 1.
  11820.     lastIndex _ 0.!
  11821. turnOffNotesAt: time
  11822.     "Turns off all notes in the active list with times at or before the given time."
  11823.  
  11824.     [(activeNotes size > 0) and:
  11825.      [(activeNotes first offTime) <= time]] whileTrue:
  11826.         [activeNotes removeFirst turnOff].! !
  11827.  
  11828. !Score methodsFor: 'conducting'!
  11829. conduct: voiceList
  11830.     "Conduct the given voices of this score. That is, watch for incoming Midi note-on and note-off events and play one chord or note of the score for each note-on event, at the velocity given by the note-on event. The pitches of the note-on and -off events are irrelevant. This works best with velocity-sensitive keyboards and in situations where the keyboard used for conducting is does not cause notes to be sounded. If voiceList is not nil, only the given voices will be played."
  11831.  
  11832.     | keyboard voices |
  11833.     "set of voices to play"
  11834.     (voiceList notNil) ifTrue:
  11835.         [voices _ Set new: 20.
  11836.          voices addAll: voiceList.
  11837.          self detect: [: event | (event isNote) & (voices includes: event voice)]
  11838.              ifNone: [^self error: 'Sorry, this score has no notes in the given voices.']].
  11839.  
  11840.     "initialize state for scanning the score"
  11841.     noteCount _ self size.
  11842.     nextIndex _ 1.
  11843.     activeNotes _ OrderedCollection new.
  11844.  
  11845.     keyboard _ MidiRecorder new.
  11846.     "ignore key pressure, control-change, program change, channel pressure, and pitch wheel change commands"
  11847.     #(160 176 192 208 224) do: [: cmd | keyboard ignoreCmd: cmd].
  11848.     keyboard midiDo: [: cmd : arg1 : arg2 |
  11849.         (((cmd bitAnd: 144) == 144) & (arg2 ~~ 0)) ifTrue:
  11850.             [self playNextChord: voices velocity: arg2]].
  11851.  
  11852.     activeNotes _ nil.
  11853.     Midi allNotesOff.!
  11854. playNextChord: voiceSet velocity: velocity
  11855.     "Play the next chord in me and remember the notes I've turned on in activeNotes. If voiceSet is not nil, play only the voices given."
  11856.  
  11857.     | nextEvent t |
  11858.     "turn of the last chord"
  11859.     self turnOffChord.
  11860.  
  11861.     "scan for the next chord we can play"
  11862.     nextEvent _ self at: nextIndex.
  11863.     [(nextEvent isNote) and:
  11864.      [(voiceSet == nil) or: [voiceSet includes: nextEvent voice]]] whileFalse:
  11865.          [nextIndex _ (nextIndex \\ noteCount) + 1.
  11866.           nextEvent _ self at: nextIndex].
  11867.  
  11868.     "collect the notes in this chord"
  11869.     t _ nextEvent time.
  11870.     [nextEvent time == t] whileTrue:
  11871.         [((nextEvent isNote) and:
  11872.           [(voiceSet == nil) or: [voiceSet includes: nextEvent voice]]) ifTrue:
  11873.             [activeNotes add: nextEvent].
  11874.          nextIndex _ (nextIndex \\ noteCount) + 1.
  11875.          nextEvent _ self at: nextIndex].
  11876.  
  11877.     "sound the chord"
  11878.     activeNotes do:
  11879.         [: note |
  11880.          Midi
  11881.             noteOn: (note pitch)
  11882.             vel: (velocity min: 127)
  11883.             chan: (note voice)].!
  11884. turnOffChord
  11885.     "Remove and turn off the the notes in activeNotes."
  11886.  
  11887.     activeNotes do: [: note | note turnOff].
  11888.     activeNotes setIndices.! !
  11889.  
  11890. MusicEventQueue comment:
  11891. 'I am a ''priority queue'' data structure stored as a heap. The basic operations on a priority queue are add: and removeFirst. At any given time, removeFirst answers the highest priority element in the queue. Elements may be ordered according to the default ''<'' relation (which gives higher priority to smaller elements) or the client may supply a sort block that takes two elements and evaluates to true if the first has higher priority than the second. I am a subclass of collection and thus support do:, collect:, and so on but it should be noted that elements are not stored in completely sorted order internally, so the iteration will not process elements in strict priority order. It should also be noted that I do NOT support random access to my elements; only the highest priority element may be examined (with ''first'') or removed (with ''removeFirst'').'!
  11892.  
  11893. !MusicEventQueue methodsFor: 'public'!
  11894. add: newElement
  11895.     "Insert the given element in the receiver at the proper location."
  11896.  
  11897.     (last == contents size) ifTrue:
  11898.         ["queue is full, so double the size of 'contents' to make room"
  11899.          contents _ (Array new: (last * 2))
  11900.             replaceFrom: 1 to: last with: contents startingAt: 1].
  11901.     last _ last + 1.
  11902.     contents at: last put: newElement.
  11903.     self pushUpFrom: last.!
  11904. do: aBlock
  11905.     "Evaluate aBlock with each of the receiver's elements as the argument."
  11906.  
  11907.     | i |
  11908.     i _ 1.
  11909.     [i <= last] whileTrue:
  11910.         [aBlock value: (contents at: i).
  11911.          i _ i + 1].!
  11912. first
  11913.     "Answer the least element of the receiver without removing it."
  11914.  
  11915.     (last == 0) ifTrue: [^self errorEmptyCollection].
  11916.     "The root is the smallest element."
  11917.     ^contents at: 1!
  11918. isEmpty
  11919.     "Answer true if the queue is empty."
  11920.  
  11921.     ^last == 0!
  11922. remove: oldObject ifAbsent: anExceptionBlock
  11923.  
  11924.     self shouldNotImplement.!
  11925. removeAll
  11926.     "Make the receiver empty."
  11927.  
  11928.     last _ 0.!
  11929. removeFirst
  11930.     "Remove and answer the least element of the receiver."
  11931.  
  11932.     | smallest oldLast |
  11933.     (last == 0) ifTrue: [^self errorEmptyCollection].
  11934.  
  11935.     "The root is the smallest element."
  11936.     smallest _ contents at: 1.
  11937.  
  11938.     "Remove the last element and replace the root it. Then push it down."
  11939.     oldLast _ contents at: last.
  11940.     contents at: last put: nil.
  11941.     last _ last - 1.
  11942.     contents at: 1 put: oldLast.
  11943.     self pushDownFrom: 1.
  11944.     ^smallest!
  11945. size
  11946.     "Answer how many elements the receiver contains."
  11947.  
  11948.     ^last!
  11949. sortBlock: aBlock
  11950.     "Register a custom sort block. The block should take two arguments, elements of the receiver, and evaluate to true if the first is less than the second (to sort smallest first) or vice versa (to sort largest first)."
  11951.  
  11952.     sortBlock _ aBlock.! !
  11953.  
  11954. !MusicEventQueue methodsFor: 'private'!
  11955. element: e1 precedes: e2
  11956.     "Answer true if element e1 precedes element e2 under the ordering relation. Use 'sortBlock' if the user supplied one, otherwise use '<' operator to directly compare the elements."
  11957.  
  11958.     ^(sortBlock == nil)
  11959.         ifTrue: [e1 < e2]
  11960.         ifFalse: [sortBlock value: e1 value: e2]!
  11961. initialize: initialSize
  11962.     "Allocate initial space for the given number of elements."
  11963.  
  11964.     contents _ Array new: initialSize.
  11965.     last _ 0.
  11966.     sortBlock _ nil.!
  11967. pushDownFrom: index
  11968.     "Push the element at index i down through the tree until it is smaller than its children or until it is a leaf with no children."
  11969.  
  11970.     | leaves parent left right child parentElement childElement |
  11971.     leaves _ last bitShift: -1.
  11972.     parent _ index.
  11973.     [parent <= leaves] whileTrue:    "while parent is not a leaf:"
  11974.         [left _ parent bitShift: 1.
  11975.          right _ left + 1.
  11976.          (left == last)
  11977.             ifTrue:
  11978.                 ["left is an only-child"
  11979.                  child _ left]
  11980.             ifFalse:
  11981.                  ["select the smaller child"
  11982.                  (self element: (contents at: left) precedes: (contents at: right))
  11983.                     ifTrue: [child _ left]
  11984.                     ifFalse: [child _ right]].
  11985.          parentElement _ contents at: parent.
  11986.          childElement _ contents at: child.
  11987.          (self element: childElement precedes: parentElement)
  11988.             ifTrue:
  11989.                 ["child is smaller, so push parent down to next level"
  11990.                  contents at: parent put: childElement.
  11991.                  contents at: child put: parentElement.
  11992.                  parent _ child]
  11993.             ifFalse:
  11994.                 ["parent is smaller than its children; cannot push farther"
  11995.                  ^self]].
  11996.     "pushed all the way to a leaf"
  11997.     ^self!
  11998. pushUpFrom: index
  11999.     "Push the element at the given index up through the tree until it is smaller than its children or until it is the root."
  12000.  
  12001.     | child parent childElement parentElement |
  12002.     child _ index.
  12003.     [(child == 1) ifTrue: [^self].    "child is the root, so it has no parent"
  12004.      parent _ child bitShift: -1.
  12005.      childElement _ contents at: child.
  12006.      parentElement _ contents at: parent.
  12007.      (self element: childElement precedes: parentElement)] whileTrue:
  12008.         [contents at: child put: parentElement.
  12009.          contents at: parent put: childElement.
  12010.          child _ parent].! !
  12011.  
  12012. !TracedCollection methodsFor: 'initialize-release'!
  12013. contentsClass: collectionClass
  12014.  
  12015.     | traceSize |
  12016.     contents _ collectionClass new.
  12017.     traceSize _ 100.
  12018.     ops _ Array new: traceSize withAll: #empty.
  12019.     args _ Array new: traceSize withAll: nil.
  12020.     ids _ Array new: traceSize withAll: 0.
  12021.     oldest _ 1.! !
  12022.  
  12023. !TracedCollection methodsFor: 'testing'!
  12024. includes: anObject 
  12025.     "Answer whether anObject is one of the receiver's elements."
  12026.  
  12027.     ^contents includes: anObject!
  12028. occurrencesOf: anObject 
  12029.     "Answer how many of the receiver's elements are equal to anObject."
  12030.  
  12031.     ^contents occurrencesOf: anObject! !
  12032.  
  12033. !TracedCollection methodsFor: 'accessing'!
  12034. at: anIndex
  12035.  
  12036.     ^contents at: anIndex!
  12037. contents
  12038.  
  12039.     ^contents!
  12040. size
  12041.  
  12042.     ^contents size!
  12043. species
  12044.  
  12045.     ^contents species! !
  12046.  
  12047. !TracedCollection methodsFor: 'adding'!
  12048. add: newObject
  12049.  
  12050.     contents add: newObject.
  12051.     self record: #add on: newObject.!
  12052. addFirst: newObject
  12053.  
  12054.     contents addFirst: newObject.
  12055.     self record: #add on: newObject.!
  12056. addLast: newObject
  12057.  
  12058.     contents addLast: newObject.
  12059.     self record: #add on: newObject.!
  12060. newContents: aCollection 
  12061.     "Replace my contents with the contents of the given collection."
  12062.  
  12063.     contents _ contents species new: (aCollection size).
  12064.     contents addAll: aCollection.
  12065.     self record: #resynch on: nil.!
  12066. updateContents: aCollection 
  12067.     "Update my contents to be consistent with the given collection."
  12068.  
  12069.     aCollection do: [: el | (contents includes: el) ifFalse: [self add: el]].
  12070.     contents copy do: [: el | (aCollection includes: el) ifFalse: [self remove: el ifAbsent: []]].! !
  12071.  
  12072. !TracedCollection methodsFor: 'removing'!
  12073. remove: oldObject ifAbsent: anExceptionBlock 
  12074.  
  12075.     contents remove: oldObject ifAbsent: anExceptionBlock.
  12076.     self record: #remove on: oldObject.!
  12077. removeAll
  12078.     "Remove all elements and reset myself to a pristine state."
  12079.  
  12080.     (contents size < ops size)
  12081.         ifTrue:
  12082.             [contents copy do:
  12083.                 [: el | self remove: el ifAbsent: []]]
  12084.         ifFalse:
  12085.             [contents _ contents species new: (contents basicSize).
  12086.              self record: #resynch on: nil].! !
  12087.  
  12088. !TracedCollection methodsFor: 'enumerating'!
  12089. do: aBlock
  12090.  
  12091.     contents do: aBlock.! !
  12092.  
  12093. !TracedCollection methodsFor: 'printing'!
  12094. storeOn: aStream
  12095.  
  12096.     self error: 'Not Implemented'.! !
  12097.  
  12098. !TracedCollection methodsFor: 'copying'!
  12099. copy
  12100.  
  12101.     ^(TracedCollection contentsClass: contents species)
  12102.         newContents: contents! !
  12103.  
  12104. !TracedCollection methodsFor: 'tracing'!
  12105. doAdds: addBlock removes: removeBlock since: id synchBlock: synchBlock
  12106.     "Process all operations on this collection since the operation with the given id. addBlock(removeBlock) is called for each add(remove) operation in sequence and is passed the added(removed) element. If the history doesn't contain an entry with uid, or contains a #synch operation, then invoke synchBlock to resynchronize the client. Answer the uid of the most recent history entry."
  12107.  
  12108.     | histSize mostRecent mostRecentID i |
  12109.     histSize _ ops size.
  12110.     mostRecent _ (oldest == 1) ifTrue: [histSize] ifFalse: [oldest - 1].
  12111.     mostRecentID _ ids at: mostRecent.
  12112.     (id == mostRecentID) ifTrue: [^mostRecentID].
  12113.     i _ ids indexOf: (id + 1).
  12114.     (i == 0)
  12115.         ifTrue: [synchBlock value]        "too much has happened; re-synch"
  12116.         ifFalse:
  12117.             [["process at least one entry"
  12118.               (self processAt: i add: addBlock remove: removeBlock) ifFalse:
  12119.                 [synchBlock value.
  12120.                  ^mostRecentID].
  12121.              i _ (i == histSize) ifTrue: [1] ifFalse: [i + 1].
  12122.              i ~~ oldest] whileTrue: ["process until we wrap around to oldest"]].
  12123.     ^mostRecentID!
  12124. processAt: index add: addBlock remove: removeBlock
  12125.     "Process the trace entry at the given index, invoking the appropriate client block. Answer true if the operation is #add or #remove, false otherwise (which means that we must re-synchronize)."
  12126.  
  12127.     | op |
  12128.     op _ ops at: index.
  12129.     (op == #add) ifTrue: [addBlock value: (args at: index). ^true].
  12130.     (op == #remove) ifTrue: [removeBlock value: (args at: index). ^true].
  12131.     ^false!
  12132. record: operation on: element
  12133.     "Record the given operation on the given element along with a unique ID."
  12134.     "Details: The collection history is a circular buffer ordered from least to most recent. The index of the oldest entry is 'oldest'. This is the entry that will next be recorded over. The entry immediately preceding the oldest entry (modulo the history size) is the most recent. The length of the history is fixed at initialization time."
  12135.  
  12136.     | histSize mostRecent |
  12137.     histSize _ ops size.
  12138.     mostRecent _ (oldest == 1) ifTrue: [histSize] ifFalse: [oldest - 1].
  12139.     ops at: oldest put: operation.
  12140.     args at: oldest put: element.
  12141.     ids at: oldest put: ((ids at: mostRecent) + 1).
  12142.     oldest _ ((oldest == histSize) ifTrue: [1] ifFalse: [oldest + 1]).! !
  12143.  
  12144. !ChangeScanner methodsFor: 'file scanning'!
  12145. scanSpecialDo: aBlock
  12146.     "Scan a chunk of file beginning with a !!.  For now, the only thing I understand is method definitions."
  12147.     | class category tmp |
  12148.     (class _ self nextClass) notNil ifTrue:
  12149.         [(tokenType == #keyword and: [token = 'methodsFor:']) ifTrue:
  12150.             [self scanToken.
  12151.             tokenType == #string ifTrue:
  12152.                 [category _ token.
  12153.                 self scanToken.
  12154.                 tokenType == #doIt ifTrue:
  12155.                     [^self scanMethodsClass: class category: category asSymbol do: aBlock]]]].
  12156. "Now, thanks to Bjorn Freeman-Benson and John Maloney, I understand class reorganizations as well."
  12157. (tokenType == #word and: [token = 'reorganize'])
  12158.     ifTrue:
  12159.         [self scanToken.
  12160.         tmp _ (ClassReorgChange file: file position: file position)
  12161.             className: class ; type: #reorganize.
  12162.         self nextChunkStream.
  12163.         ^aBlock value: tmp].
  12164.     "I don't understand what's on the file.  Scan for a blank chunk and hope for the best."
  12165.     [self nextChunkStream atEnd] whileFalse: []! !
  12166.  
  12167. ScoreElement comment:
  12168. 'ScoreElement is an abstract superclass for things that can be placed in scores, such as NoteElements, NoteOffs, ProgramChanges, ControlChanges, and so forth. The salient feature of all ScoreElements is that they all have a time and can be sorted accordingly.'!
  12169.  
  12170. !ScoreElement methodsFor: 'accessing'!
  12171. time
  12172.     "Answer the performance time of this ScoreElement in centiseconds."
  12173.  
  12174.     ^time!
  12175. time: newTime
  12176.     "Set the performance time of this ScoreElement to the given time."
  12177.  
  12178.     time _ newTime.! !
  12179.  
  12180. !ScoreElement methodsFor: 'testing'!
  12181. isNote
  12182.  
  12183.     ^false! !
  12184.  
  12185. !ScoreElement methodsFor: 'comparing'!
  12186. < aScoreElement
  12187.     "Answer true if I am at an earlier time than aScoreElement."
  12188.  
  12189.     ^self time < aScoreElement time!
  12190. <= aScoreElement
  12191.     "Answer true if I am at an earlier or the same time as aScoreElement."
  12192.  
  12193.     ^self time <= aScoreElement time!
  12194. > aScoreElement
  12195.     "Answer true if I am at a later time than aScoreElement."
  12196.  
  12197.     ^self time > aScoreElement time!
  12198. >= aScoreElement
  12199.     "Answer true if I am at a later or the same time as aScoreElement."
  12200.  
  12201.     ^self time >= aScoreElement time! !
  12202.  
  12203. !ScoreElement methodsFor: 'performing'!
  12204. perform
  12205.     "Perform myself. This is a placeholder that subclasses override to actually do something."
  12206.  
  12207.     self subclassResponsibility! !
  12208.  
  12209. NoteElement comment:
  12210. 'I am a subclass of ScoreElement that represents a soundable note. In order to allow one to fit larger scores in memory, my space is optimized at a very slight cost in additional access time. I pack three of my attributes into one instance SmallInteger instance variable as follows:
  12211.  
  12212.     my voice (0-31) -- lowest 5 bits of velocityPitchVoice
  12213.     my pitch (0-127) -- next 7 bits of velocityPitchVoice
  12214.     my velocity (0-127) -- next 7 bits of velocityPitchVoice
  12215. '!
  12216.  
  12217. !NoteElement methodsFor: 'initialize-release'!
  12218. initialize
  12219.     "Initialize myself with reasonable default parameters."
  12220.  
  12221.     time _ 0.
  12222.     velocityPitchVoice _ 309121.
  12223.     duration _ 60.
  12224.  
  12225.     "the above is equivalent to:
  12226.         velocityPitchVoice _ 0.
  12227.         self time: 0; pitch: 60; velocity: 75; dur: 60; voice: 1."!
  12228. vel: vel pitch: pitch voice: voice
  12229.     "Initialize myself with the given velocity, pitch, and voice and a reasonable default time and duration."
  12230.  
  12231.     time _ 0.
  12232.     duration _ 60.
  12233.     velocityPitchVoice _
  12234.         (((vel bitAnd: 127) bitShift: 12) bitOr:
  12235.          ((pitch bitAnd: 127) bitShift: 5)) bitOr:
  12236.           (voice bitAnd: 31).
  12237.  
  12238.     "the above is equivalent to:
  12239.         self time: 0; pitch: 60; velocity: 75; dur: 60; voice: 1."! !
  12240.  
  12241. !NoteElement methodsFor: 'accessing'!
  12242. dur
  12243.  
  12244.     ^duration!
  12245. dur: newDur
  12246.  
  12247.     duration _ newDur.!
  12248. offTime
  12249.  
  12250.     ^time + duration!
  12251. pitch
  12252.  
  12253.     ^(velocityPitchVoice bitShift: -5) bitAnd: 127!
  12254. pitch: newPitch
  12255.  
  12256.     velocityPitchVoice _
  12257.         ((newPitch bitAnd: 127) bitShift: 5) bitOr:
  12258.             (velocityPitchVoice bitAnd: 520223 "(127 bitShift: 12) + 31").!
  12259. velocity
  12260.  
  12261.     ^velocityPitchVoice bitShift: -12!
  12262. velocity: newVelocity
  12263.  
  12264.     velocityPitchVoice _
  12265.         ((newVelocity bitAnd: 127) bitShift: 12) bitOr:
  12266.             (velocityPitchVoice bitAnd: 4095 "low 7+5 bits").!
  12267. voice
  12268.  
  12269.     ^velocityPitchVoice bitAnd: 31!
  12270. voice: newVoice
  12271.  
  12272.     velocityPitchVoice _
  12273.         (newVoice bitAnd: 31) bitOr:
  12274.             (velocityPitchVoice bitAnd: -32 "all but lowest 5 bits").! !
  12275.  
  12276. !NoteElement methodsFor: 'testing'!
  12277. isNote
  12278.  
  12279.     ^true! !
  12280.  
  12281. !NoteElement methodsFor: 'performing'!
  12282. perform
  12283.     "Perform myself."
  12284.  
  12285.     Midi
  12286.         noteOn: (self pitch)
  12287.         vel: (self velocity)
  12288.         chan: (self voice).!
  12289. turnOff
  12290.     "Turn myself off."
  12291.  
  12292.     Midi
  12293.         noteOn: (self pitch)
  12294.         vel: 0
  12295.         chan: (self voice).! !
  12296.  
  12297. !NoteElement methodsFor: 'print/store'!
  12298. adagioPitchString
  12299.     "Translate my pitch to a symbolic pitch. Having no concept of key signature, we choose a note spelling arbitrarily. Note: Pitches use the CMU Midi Toolkit standard of middle C = 48 versus the Midi standard of middle C = 60. For example, C4 = P48 is middle C, B3 = P47 is the B half a step below that, and the top and bottom notes of a piano are A0 = P9 and C9 = P108 respectively. The full Midi range is P-12 to P115."
  12300.  
  12301.     | octave name |
  12302.     octave _ (self pitch // 12) - 1.
  12303.     name _ #(c cs d ef e f fs g gs a bf b) at: ((self pitch \\ 12) + 1).
  12304.     ^name asString, octave printString!
  12305. printOn: aStream
  12306.  
  12307.     self storeAdagioOn: aStream previous: nil next: nil.!
  12308. storeAdagioOn: aStream previous: previousTone next: nextTone
  12309.     "Write an Adagio language description of myself to the given stream. To allow nicer printing, the notes immediately preceding and following me in my voice are supplied if they exist (otherwise nil is supplied instead)."
  12310.  
  12311.     | deltaTime |
  12312.     (previousTone isNil) ifTrue:
  12313.         [aStream nextPutAll:
  12314.             't', self time printString,
  12315.             ' ', self adagioPitchString,
  12316.             ' u', self dur printString,
  12317.             ' l', self velocity printString,
  12318.             ' v', self voice printString]
  12319.         ifFalse: 
  12320.             [aStream nextPutAll: self adagioPitchString.
  12321.              (self dur ~= previousTone dur)
  12322.                 ifTrue: [aStream nextPutAll: ' u', self dur printString].
  12323.              (self velocity ~= previousTone velocity)
  12324.                  ifTrue: [aStream nextPutAll: ' l', self velocity printString].
  12325.              (self voice ~= previousTone voice)
  12326.                 ifTrue: [aStream nextPutAll: ' v', self voice printString]].
  12327.     (nextTone isNil)
  12328.         ifTrue: [aStream cr]
  12329.         ifFalse:
  12330.             [deltaTime _ nextTone time - self time.
  12331.              (deltaTime == 0)
  12332.                 ifTrue: [aStream nextPutAll: ', ']
  12333.                 ifFalse:
  12334.                     [(deltaTime ~~ self dur)
  12335.                         ifTrue:
  12336.                             [aStream nextPutAll: ' n', deltaTime printString.
  12337.                              aStream cr]
  12338.                         ifFalse: [aStream cr]]].! !
  12339.  
  12340. NoteOff comment:
  12341. 'I am a subclass of ScoreElement that represents a note-off event.'!
  12342.  
  12343. !NoteOff methodsFor: 'accessing'!
  12344. pitch
  12345.  
  12346.     ^pitch!
  12347. pitch: aPitch
  12348.  
  12349.     pitch _ aPitch.!
  12350. voice
  12351.  
  12352.     ^voice!
  12353. voice: aVoice
  12354.  
  12355.     voice _ aVoice.! !
  12356.  
  12357. !NoteOff methodsFor: 'performing'!
  12358. perform
  12359.     "Perform myself."
  12360.  
  12361.     Midi noteOff: pitch chan: voice.! !
  12362.  
  12363. !Browser methodsFor: 'text'!
  12364. textMenu
  12365.     "Browser flushMenus"
  12366.     TextMenu == nil ifTrue:
  12367.         [TextMenu _ ActionMenu
  12368.             labelList: #((again undo) (copy cut paste) ('do it' 'print it' inspect) (accept cancel) (format spawn explain) ('edit form'))
  12369.             selectors: #(again undo copySelection cut paste doIt printIt inspectIt accept cancel format spawnEdits:from: explain formEdit)].
  12370.     ^ TextMenu! !
  12371.  
  12372. !FileModel methodsFor: 'text'!
  12373. textMenu 
  12374.     "FileModel flushMenus"
  12375.     fileName == nil ifTrue: [^ nil].
  12376.     TextMenu == nil ifTrue:
  12377.         [TextMenu _ ActionMenu
  12378.             labelList: #((again undo) (copy cut paste) ('do it' 'print it' inspect) ('file it in' put get ) (spawn) ('edit form'))
  12379.             selectors: #(again undo copySelection cut paste doIt printIt inspectIt fileItIn:from: accept getNew:from: spawnFile:from: formEdit)].
  12380.     ^ TextMenu! !
  12381.  
  12382. !HierarchicalFileList methodsFor: 'text'!
  12383. textMenu 
  12384.     isDirectory ifFalse: [^super textMenu].
  12385.     fileName == nil ifTrue: [^ nil].
  12386.     ^ActionMenu
  12387.             labelList: #((again undo) (copy cut paste) ('do it' 'print it' inspect) ('edit form'))
  12388.             selectors: #(again undo copySelection cut paste doIt printIt inspectIt formEdit)! !
  12389.  
  12390. Scene comment:
  12391. 'A Scene is a two-dimensional diagram or picture composed of displayable objects called glyphs. Each glyph must respond to the basic protocol for Glyphs (see class Glyph). A scene also maintains a list of selected glyphs and can enumerate various kinds of the glyphs: visible, selectable, and input-accepting.
  12392. '!
  12393.  
  12394. !Scene methodsFor: 'initialize-release'!
  12395. initialize
  12396.  
  12397.     glyphs _ FreeVariable value:
  12398.         (TracedCollection contentsClass: OrderedCollection).
  12399.     selected _ IdentitySet new.
  12400.     viewWidth _ FreeVariable new.
  12401.     viewHeight _ FreeVariable new.
  12402.     viewWidth strongPreferredStay.
  12403.     viewHeight strongPreferredStay.! !
  12404.  
  12405. !Scene methodsFor: 'accessing'!
  12406. constraintCount
  12407.     "Answer the total number of constraints used in this scene."
  12408.  
  12409.     | constraints |
  12410.     constraints _ IdentitySet new.
  12411.     self topLevelGlyphsDo:
  12412.         [: g |
  12413.          g varsDo:
  12414.             [: v | constraints addAll: v constraints]].
  12415.     ^constraints size!
  12416. viewHeightVar
  12417.  
  12418.     ^viewHeight!
  12419. viewWidthVar
  12420.  
  12421.     ^viewWidth! !
  12422.  
  12423. !Scene methodsFor: 'testing'!
  12424. isAnimated
  12425.     "This message should really be implemented with some other mechanism such as 
  12426.     looking at all the constraints and return true if any span time boundries."
  12427.  
  12428.     ^false! !
  12429.  
  12430. !Scene methodsFor: 'glyphs access'!
  12431. glyphsVar
  12432.  
  12433.     ^glyphs!
  12434. inputGlyphsDo: aBlock
  12435.     "Evaluate the given block on all input glyphs in this scene."
  12436.  
  12437.     self topLevelGlyphsDo:
  12438.         [: g | g inputGlyphsDo: aBlock].!
  12439. selectableGlyphsDo: aBlock
  12440.     "Evaluate the given block on all selectable glyphs in this scene."
  12441.  
  12442.     self topLevelGlyphsDo:
  12443.         [: g | g selectableGlyphsDo: aBlock].!
  12444. topLevelGlyphs
  12445.     "Answer my top level glyphs."
  12446.  
  12447.     ^glyphs value!
  12448. topLevelGlyphsDo: aBlock
  12449.     "Evaluate the given block for all my top-level glyphs."
  12450.  
  12451.     | topGlyphs count i |
  12452.     topGlyphs _ self topLevelGlyphs.
  12453.     count _ topGlyphs size.
  12454.     i _ 1.
  12455.     [i <= count] whileTrue:
  12456.         [aBlock value: (topGlyphs at: i).
  12457.          i _ i + 1].!
  12458. visibleGlyphsDo: aBlock
  12459.     "Evaluate the given block on all visible glyphs in this scene."
  12460.  
  12461.     self topLevelGlyphsDo:
  12462.         [: g | g visibleGlyphsDo: aBlock].! !
  12463.  
  12464. !Scene methodsFor: 'glyphs'!
  12465. addGlyph: aGlyph
  12466.  
  12467.     glyphs changeIn:
  12468.         [glyphs value addLast: aGlyph].!
  12469. moveToFront: aGlyph
  12470.  
  12471.      | topLevel |
  12472.     glyphs changeIn:
  12473.         [topLevel _ true.
  12474.          glyphs value remove: aGlyph ifAbsent: [topLevel _ false].
  12475.          topLevel
  12476.             ifTrue: [glyphs value addLast: aGlyph]].!
  12477. moveToRear: aGlyph
  12478.  
  12479.      | topLevel |
  12480.     glyphs changeIn:
  12481.         [topLevel _ true.
  12482.          glyphs value remove: aGlyph ifAbsent: [topLevel _ false].
  12483.          topLevel
  12484.             ifTrue: [glyphs value addFirst: aGlyph]].!
  12485. removeGlyph: aGlyph
  12486.  
  12487.     glyphs changeIn:
  12488.         [glyphs value remove: aGlyph ifAbsent: [].
  12489.          selected remove: aGlyph ifAbsent: []].! !
  12490.  
  12491. !Scene methodsFor: 'selections'!
  12492. clearSelection
  12493.  
  12494.     selected _ selected species new.!
  12495. deselect: aGlyph
  12496.  
  12497.     selected remove: aGlyph ifAbsent: [].!
  12498. select: aGlyph
  12499.  
  12500.     selected add: aGlyph.!
  12501. selected
  12502.  
  12503.     ^selected!
  12504. toggleSelect: aGlyph
  12505.     "Toggle the selection of aGlyph. That is, if aGlyph is currently selected, deselect it; if it is not selected, select it."
  12506.  
  12507.     (selected includes: aGlyph)
  12508.         ifTrue: [self deselect: aGlyph]
  12509.         ifFalse: [self select: aGlyph]! !
  12510.  
  12511. !Scene methodsFor: 'background processing'!
  12512. backgroundTask: theView 
  12513.     "The controller sends this message to the model when nothing else is happening. 
  12514.     This allows the model to do background processing to support, for example, a 
  12515.     simulation or an animation."
  12516.  
  12517.     ^self!
  12518. computeBackgroundPlan
  12519.     "The controller sends this message to the model when it wants to create a plan 
  12520.     to animate things when nothing else is going on."
  12521.  
  12522.     ^nil!
  12523. initialAnimationConstraints
  12524.     "The controller sends this message to the model when it wants to create a plan 
  12525.     to animate things when something is going on."
  12526.  
  12527.     ^#()! !
  12528.  
  12529. !AnchorLine3Demo methodsFor: 'initialize-release'!
  12530. create
  12531.     | l f |
  12532.     Transcript cr; show: 'Building the ' , self class name , '..'.
  12533.     Transcript cr; show: '..adding the components'.
  12534.     f _ SIGGRAPHAnchorGlyph new initialize.
  12535.     l _ LineGlyph new.
  12536.     l moveTo: 100 @ 100.
  12537.     self addGlyph: f; addGlyph: l.
  12538.     Transcript cr; show: '..adding the consistency constraints'.
  12539.     EqualityConstraint
  12540.         var: l p1 yVar
  12541.         var: l p2 yVar
  12542.         strength: #required.
  12543.     EqualityConstraint
  12544.         var: l p1 xVar
  12545.         var: f xVar
  12546.         strength: #required.
  12547.     EqualityConstraint
  12548.         var: l p1 yVar
  12549.         var: f yVar
  12550.         strength: #required.
  12551.     StayConstraint var: f xVar strength: #default.
  12552.     StayConstraint var: f yVar strength: #default.
  12553.     Transcript cr; show: 'finished'!
  12554. initialize
  12555.     super initialize.
  12556.     self create! !
  12557.  
  12558. !AnchorLine3Demo methodsFor: 'public'!
  12559. open
  12560.     "AnchorLine3Demo new open"
  12561.  
  12562.     | topView |
  12563.     topView _ SpecialSystemView
  12564.                 model: nil
  12565.                 label: 'Horizontal Line, Anchor, Strong Mouse'
  12566.                 minimumSize: 300 @ 200.
  12567.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  12568.     topView controller open! !
  12569.  
  12570. !AnchorLine2Demo methodsFor: 'initialize-release'!
  12571. create
  12572.     | l f |
  12573.     Transcript cr; show: 'Building the ' , self class name , '..'.
  12574.     Transcript cr; show: '..adding the components'.
  12575.     f _ SIGGRAPHAnchorGlyph new initialize.
  12576.     l _ LineGlyph new.
  12577.     l moveTo: 100 @ 100.
  12578.     self addGlyph: f; addGlyph: l.
  12579.     Transcript cr; show: '..adding the consistency constraints'.
  12580.     EqualityConstraint
  12581.         var: l p1 yVar
  12582.         var: l p2 yVar
  12583.         strength: #required.
  12584.     EqualityConstraint
  12585.         var: l p1 xVar
  12586.         var: f xVar
  12587.         strength: #required.
  12588.     EqualityConstraint
  12589.         var: l p1 yVar
  12590.         var: f yVar
  12591.         strength: #required.
  12592.     StayConstraint var: f xVar strength: #strongPreferred.
  12593.     StayConstraint var: f yVar strength: #strongPreferred.
  12594.     Transcript cr; show: 'finished'!
  12595. initialize
  12596.     super initialize.
  12597.     self create! !
  12598.  
  12599. !AnchorLine2Demo methodsFor: 'public'!
  12600. open
  12601.     "AnchorLine2Demo new open"
  12602.  
  12603.     | topView |
  12604.     topView _ SpecialSystemView
  12605.                 model: nil
  12606.                 label: 'Horizontal Line, Anchor'
  12607.                 minimumSize: 300 @ 200.
  12608.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  12609.     topView controller open! !
  12610.  
  12611. !RaisingDemo methodsFor: 'initialize-release'!
  12612. create
  12613.     | hl vl m c |
  12614.     Transcript cr; show: 'Building the ' , self class name , '..'.
  12615.     Transcript cr; show: '..adding the components'.
  12616.     m _ FakeMouseGlyph new initialize.
  12617.     hl _ LineGlyph new.
  12618.     hl moveTo: 100 @ 100.
  12619.     vl _ LineGlyph new.
  12620.     vl moveTo: 100 @ 150.
  12621.     self addGlyph: m; addGlyph: hl; addGlyph: vl.
  12622.     Transcript cr; show: '..adding the consistency constraints'.
  12623.     EqualityConstraint
  12624.         var: hl p1 yVar
  12625.         var: hl p2 yVar
  12626.         strength: #weakDefault.
  12627.     EqualityConstraint
  12628.         var: vl p1 xVar
  12629.         var: vl p2 xVar
  12630.         strength: #required.
  12631.     (Constraint names: #(y1 y1p y2 y2p)
  12632.         methods: #('y1 _ y1p' 'y2 _ y2p'))
  12633.             var: vl p1 yVar
  12634.             var: vl p1 yVar last
  12635.             var: vl p2 yVar
  12636.             var: vl p2 yVar last
  12637.             strength: #required.
  12638.     EqualityConstraint
  12639.         var: hl p1 yVar
  12640.         var: vl p1 yVar
  12641.         strength: #required.
  12642.     EqualityConstraint
  12643.         var: hl p1 xVar
  12644.         var: vl p1 xVar
  12645.         strength: #required.
  12646.     EqualityConstraint
  12647.         var: vl p2 xVar
  12648.         var: m xVar
  12649.         strength: #required.
  12650.     EqualityConstraint
  12651.         var: vl p2 yVar
  12652.         var: m yVar
  12653.         strength: #required.
  12654.     "c _ Constraint names: #(new old ) methods: #('new _ ((old + SplittingDemo nextRandom) min: 350) max: 5' ).
  12655.     fakemouse _ Array with: (c copy
  12656.                     var: m xVar
  12657.                     var: m xVar last
  12658.                     strength: #default)
  12659.                 with: (c copy
  12660.                         var: m yVar
  12661.                         var: m yVar last
  12662.                         strength: #default)."
  12663.     fakemouse _ Array new: 2.
  12664.     fakemouse at: 1 put: ((Constraint
  12665.         names: #(new old )
  12666.         methods: #('new _ SplittingDemo nextRandomX' ))
  12667.             var: m xVar
  12668.             var: m xVar last
  12669.             strength: #default).
  12670.     fakemouse at: 2 put: ((Constraint
  12671.         names: #(new old )
  12672.         methods: #('new _ SplittingDemo nextRandomY' ))
  12673.             var: m yVar
  12674.             var: m yVar last
  12675.             strength: #default).
  12676.     Transcript cr; show: 'finished'!
  12677. initialize
  12678.     super initialize.
  12679.     self create! !
  12680.  
  12681. !RaisingDemo methodsFor: 'public'!
  12682. open
  12683.     "RaisingDemo new open"
  12684.  
  12685.     | topView |
  12686.     topView _ SpecialSystemView
  12687.                 model: nil
  12688.                 label: 'Raising'
  12689.                 minimumSize: 400 @ 400.
  12690.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  12691.     topView controller open! !
  12692.  
  12693. !RaisingDemo methodsFor: 'testing'!
  12694. isAnimated
  12695.     ^true! !
  12696.  
  12697. !RaisingDemo methodsFor: 'background processing'!
  12698. computeBackgroundPlan
  12699.     ^Planner extractPlanFromInputConstraints: fakemouse!
  12700. initialAnimationConstraints
  12701.     ^fakemouse! !
  12702.  
  12703. !MusicEditor methodsFor: 'all'!
  12704. addVoiceMenu: backgroundGlyphs
  12705.  
  12706.     | voiceMenuGlyph voiceC |
  12707.     voiceC _ Constraint
  12708.         names: #(text voice)
  12709.         methods: #(
  12710.             'text _ (voice = 0)
  12711.                 ifTrue: ['' All Voices '']
  12712.                 ifFalse: ['' Voice '', voice printString, '' '']').
  12713.     voiceMenuGlyph _ TextGlyph new
  12714.         text: '<Voice>'; font: (TextStyle default fontAt: 2).
  12715.     voiceMenuGlyph box leftVar defaultStay.
  12716.     voiceMenuGlyph moveTo: 142@19.
  12717.     voiceC
  12718.         var: voiceMenuGlyph textVar var: visibleVoice
  12719.         strength: #required.
  12720.     backgroundGlyphs add: voiceMenuGlyph.
  12721.     backgroundGlyphs add: ((AttachableMenuGlyph forHost: voiceMenuGlyph)
  12722.         addMenuEntry: 'All Voices' script: 'model setVoice: 0';
  12723.         addMenuEntry: 'Voice 1' script: 'model setVoice: 1';
  12724.         addMenuEntry: 'Voice 2' script: 'model setVoice: 2';
  12725.         addMenuEntry: 'Voice 3' script: 'model setVoice: 3';
  12726.         addMenuEntry: 'Voice 4' script: 'model setVoice: 4';
  12727.         addMenuEntry: 'Voice 5' script: 'model setVoice: 5';
  12728.         addMenuEntry: 'Voice 6' script: 'model setVoice: 6';
  12729.         addMenuEntry: 'Voice 7' script: 'model setVoice: 7';
  12730.         addMenuEntry: 'Voice 8' script: 'model setVoice: 8';
  12731.         addMenuEntry: 'Voice 9' script: 'model setVoice: 9';
  12732.         addMenuEntry: 'Voice 10' script: 'model setVoice: 10';
  12733.         addMenuEntry: 'Voice 11' script: 'model setVoice: 11';
  12734.         addMenuEntry: 'Voice 12' script: 'model setVoice: 12';
  12735.         addMenuEntry: 'Voice 13' script: 'model setVoice: 13';
  12736.         addMenuEntry: 'Voice 14' script: 'model setVoice: 14';
  12737.         addMenuEntry: 'Voice 15' script: 'model setVoice: 15';
  12738.         addMenuEntry: 'Voice 16' script: 'model setVoice: 16').!
  12739. asScore
  12740.  
  12741.     | voice noteGlyphs score |
  12742.     voice _ visibleVoice value.
  12743.     noteGlyphs _ (selected isEmpty)
  12744.         ifTrue:
  12745.             [(voice == 0)
  12746.                 ifTrue: [theScore]
  12747.                 ifFalse: [theScore select: [: g | g voice == voice]]]
  12748.         ifFalse: [selected select: [: g | g class == NoteGlyph]].
  12749.     score _ Score new.
  12750.     (noteGlyphs asSortedCollection: [: n1 : n2 | n1 start <= n2 start]) do:
  12751.         [: g |
  12752.          score addLast:
  12753.             (NoteElement
  12754.                 new: (g midiPitch) at: (g start rounded) dur: (g duration rounded)
  12755.                 vel: (g velocity rounded) voice: (g voice))].
  12756.     ^score!
  12757. backgroundTask: view
  12758.  
  12759.     | note voice |
  12760.     (midiRecorder == nil) ifTrue: [^self].
  12761.     voice _ visibleVoice value.
  12762.     (voice = 0) ifTrue: [voice _ 1].    "put in voice 1 if all voices selected"
  12763.     midiRecorder pollMidi:
  12764.         [: cmd : key : vel |
  12765.          (((cmd bitAnd: 2r11110000) == 144) and: [vel > 0]) ifTrue:
  12766.               [note _ self noteAt: scoreEndTime value dur: 60 pitch: key vel: vel voice: voice.
  12767.              scoreEndTime setValue: (scoreEndTime value + 60).
  12768.              theScore add: note]].
  12769.     (note == nil) ifFalse:
  12770.         [self updateVisibleNotes.
  12771.          view displayScene].!
  12772. backgroundView
  12773.     "Answer a variable containing a set of staff lines, buttons, etc."
  12774.  
  12775.     | lineC backgroundGlyphs key l scroller |
  12776.     lineC _ Constraint
  12777.         names: #(lineY key yOrigin ySpacing)
  12778.         methods: #('lineY _ yOrigin - (key * ySpacing)').
  12779.     backgroundGlyphs _ TracedCollection new.
  12780.     #(25 27 29 31 33 37 39 41 43 45) do:
  12781.         [: k |
  12782.          key _ FreeVariable value: k.
  12783.           l _ StaffLineGlyph new.
  12784.          l origin x: 20.
  12785.          OffsetConstraint from: (l lengthVar) to: viewWidth require: 40.
  12786.          (lineC copy)
  12787.             var: (l origin yVar) var: key var: yOrigin1 var: ySpacing
  12788.             strength: #required.
  12789.          backgroundGlyphs add: l.
  12790.           l _ StaffLineGlyph new.
  12791.          l origin x: 20.
  12792.          OffsetConstraint from: (l lengthVar) to: viewWidth require: 40.
  12793.          (lineC copy)
  12794.             var: (l origin yVar) var: key var: yOrigin2 var: ySpacing
  12795.             strength: #required.
  12796.          backgroundGlyphs add: l].
  12797.  
  12798.     backgroundGlyphs add: (TextButtonGlyph new
  12799.         text: ' Insert '; script: 'model insertNotes';
  12800.         moveTo: 36@19).
  12801.     backgroundGlyphs add: (TextButtonGlyph new
  12802.         text: ' Delete '; script: 'model deleteNotes';
  12803.         moveTo: 35@41).
  12804.     backgroundGlyphs add: (TextButtonGlyph new
  12805.         text: ' Play '; script: 'model play';
  12806.         moveTo: 84@19).
  12807.     backgroundGlyphs add: (TextButtonGlyph new
  12808.         text: ' Stop '; script: '';
  12809.         moveTo: 84@41).
  12810.  
  12811.     self addVoiceMenu: backgroundGlyphs.
  12812.  
  12813.     backgroundGlyphs add: (TextGlyph new
  12814.         text: 'Speed:'; moveTo: (140@35)).
  12815.     backgroundGlyphs add: ((HSliderGlyph on: rate)
  12816.         minVal: 0.1; maxVal: 4.0; value: 1.0;
  12817.         moveTo: 231@35).
  12818.  
  12819.     backgroundGlyphs add: (TextGlyph new
  12820.         text: 'Scale:'; moveTo: (330@19)).
  12821.     backgroundGlyphs add: ((HAtomicSliderGlyph on: timeScale)
  12822.         minVal: 0.1; maxVal: 4.0; value: 1.0;
  12823.         script: 'model updateVisibleNotes';
  12824.         moveTo: 420@19).
  12825.  
  12826.     backgroundGlyphs add: (TextGlyph new
  12827.         text: 'Scroll:'; moveTo: (330@35)).
  12828.     backgroundGlyphs add: ((scroller _ HAtomicSliderGlyph on: timeOrigin)
  12829.         minVal: 0.0; value: 0.0;
  12830.         script: 'model updateVisibleNotes';
  12831.         moveTo: 420@35).
  12832.     scoreEndTime requireEquals: scroller maxValVar.
  12833.  
  12834.     ^FreeVariable value: backgroundGlyphs!
  12835. deleteNotes
  12836.  
  12837.     | deleted visible |
  12838.     deleted _ selected select: [: g | g class == NoteGlyph].
  12839.     visibleNotes changeIn:
  12840.         [visible _ visibleNotes value.
  12841.          deleted do:
  12842.             [: note |
  12843.              visible remove: note ifAbsent: [].
  12844.              theScore remove: note ifAbsent: []]].
  12845.     self clearSelection.!
  12846. initialize
  12847.  
  12848.     | m1 m2 |
  12849.     super initialize.
  12850.     theScore _ Score new.
  12851.     visibleNotes _ FreeVariable value: (TracedCollection new).
  12852.     visibleVoice _ FreeVariable value: 0.
  12853.     yOrigin1 _ FreeVariable value: 260.
  12854.     yOrigin2 _ FreeVariable value: 380.
  12855.     ySpacing _ FreeVariable value: 4.
  12856.     xOrigin _ FreeVariable value: 22.
  12857.     timeOrigin _ FreeVariable value: 0.
  12858.     timeScale _ FreeVariable value: 1.0.
  12859.     rate _ FreeVariable value: 1.0.
  12860.     scoreEndTime _ FreeVariable value: 0.
  12861.     midiRecorder _ nil.
  12862.  
  12863.     "yOrigin1 and ySpacing are hardcoded into noteYC for efficiency"
  12864.     m1 _ 'noteY _ ', yOrigin1 value printString, ' - (key * ', ySpacing value printString, ')'.
  12865.     m2 _ 'key _ (', yOrigin1 value printString, ' - noteY) // ', ySpacing value printString.
  12866.     noteYC _ Constraint
  12867.         names: #(noteY key)
  12868.         methods: (Array with: m1 with: m2).!
  12869. insertNotes: view
  12870.  
  12871.     | voice pitch note key |
  12872.     voice _ visibleVoice value.
  12873.     (voice = 0) ifTrue: [voice _ 1].    "put in voice 1 if all voices selected"
  12874.     Cursor crossHair showWhile:
  12875.         [[Sensor anyButtonPressed] whileFalse:
  12876.             [(Sensor keyboardPressed) ifTrue:
  12877.                 [Sensor keyboard.
  12878.                  key _ ((yOrigin1 value - view controller adjustedCursorPoint y) /
  12879.                          ySpacing value) rounded.
  12880.                  "Midi noteOn: key vel: 75 chan: 1."
  12881.                  pitch _ NoteGlyph keyToPitch: key.
  12882.                    note _ self noteAt: scoreEndTime value dur: 60 pitch: pitch vel: 75 voice: voice.
  12883.                  scoreEndTime setValue: (scoreEndTime value + 60).
  12884.                  theScore add: note.
  12885.                  self updateVisibleNotes.
  12886.                  view displayScene.
  12887.                  "Midi noteOn: key vel: 0 chan: 1"]]].!
  12888. noteAt: start dur: duration pitch: pitch vel: velocity voice: voice
  12889.  
  12890.     | note keyAndMod |
  12891.     note _ NoteGlyph new.
  12892.     note start: start.
  12893.     note duration: duration.
  12894.     keyAndMod _ NoteGlyph pitchToKeyAndMod: pitch.
  12895.     note pitch: keyAndMod first.
  12896.     note modifier: keyAndMod last.
  12897.     note velocity: velocity.
  12898.     note voice: voice.
  12899.  
  12900.     "constraints"
  12901.     note center xVar strongPreferredStay.
  12902.     note startVar defaultStay.
  12903.     note pitchVar defaultStay.
  12904.     note durationVar defaultStay.
  12905.     (noteYC copy)
  12906.         var: (note center yVar) var: (note pitchVar)
  12907.         strength: #required.
  12908.     ^note!
  12909. openDemo
  12910.     "MusicEditor new openDemo"
  12911.  
  12912.     self openOn: 'c; d; e; f; g; c v2 t0; b; a; a; g' asScore.!
  12913. openOn: adagioScore
  12914.     "MusicEditor new openOn: (Score fromFile: 'bach.gio')"
  12915.  
  12916.     | oops bytes background bars notesAndBars |
  12917.     self initialize.
  12918.     theScore _ OrderedCollection new: adagioScore size.
  12919.     adagioScore do:
  12920.         [: note |
  12921.          theScore add: (self
  12922.             noteAt: note time
  12923.             dur: note dur
  12924.             pitch: note pitch
  12925.             vel: note velocity
  12926.             voice: note voice)].
  12927.     background _ self backgroundView.
  12928.     visibleNotes _ FreeVariable value: (TracedCollection new).
  12929.     bars _ self timeViewOn: visibleNotes.
  12930.     notesAndBars _ FreeVariable value: (TracedCollection new).
  12931.     SetUnionConstraint
  12932.         var: visibleNotes var: bars var: notesAndBars
  12933.         strength: #required.
  12934.     SetUnionConstraint
  12935.         var: notesAndBars var: background var: (self glyphsVar)
  12936.         strength: #required.
  12937.     viewWidth setValue: 400 strength: #required.
  12938.     self setVoice: 1.
  12939.     "self startMidiRecorder."
  12940.     SceneView openOn: self.!
  12941. play
  12942.  
  12943.     | score |
  12944.     score _ self asScore.
  12945.     score playFrom: (score first time) rate: (rate value).!
  12946. setVoice: newVoice
  12947.  
  12948.     | score |
  12949.     visibleVoice setValue: newVoice.
  12950.     score _ self asScore.
  12951.     (score size > 0)
  12952.         ifTrue: [timeOrigin setValue: (score first time)]
  12953.         ifFalse: [timeOrigin setValue: 0].
  12954.     scoreEndTime setValue: (score scoreTime max: 1).
  12955.     self updateVisibleNotes.!
  12956. startMidiRecorder
  12957.  
  12958.     midiRecorder _ MidiRecorder new startRecording.
  12959.     "ignore key after-pressure, program change, channel pressure (after-touch), and pitch wheel change commands:"
  12960.     #(160 192 208 224) do: [: cmd | midiRecorder ignoreCmd: cmd].!
  12961. testOn: adagioScore
  12962.     "MusicEditor basicNew testOn: 'c; d; e; f; g; c v2 t0; b; a; a; g' asScore.
  12963.      MusicEditor basicNew testOn: (Score fromFile: 'bach.gio')"
  12964.  
  12965.     | oops bytes background bars notesAndBars |
  12966.     self initialize.
  12967.     theScore _ OrderedCollection new: adagioScore size.
  12968.     adagioScore do:
  12969.         [: note |
  12970.          theScore add: (self
  12971.             noteAt: note time
  12972.             dur: note dur
  12973.             pitch: note pitch
  12974.             vel: note velocity
  12975.             voice: note voice)].
  12976.     background _ self backgroundView.
  12977.     visibleNotes _ FreeVariable value: (TracedCollection new).
  12978.     bars _ self timeViewOn: visibleNotes.
  12979.     notesAndBars _ FreeVariable value: (TracedCollection new).
  12980.     SetUnionConstraint
  12981.         var: visibleNotes var: bars var: notesAndBars
  12982.         strength: #required.
  12983.     SetUnionConstraint
  12984.         var: notesAndBars var: background var: (self glyphsVar)
  12985.         strength: #required.
  12986.     viewWidth setValue: 1000000 strength: #required.
  12987.     timeOrigin setValue: 0.
  12988.     scoreEndTime setValue: (adagioScore scoreTime max: 1).
  12989.     self updateVisibleNotes.!
  12990. timeViewOn: noteGlyphs
  12991.  
  12992.     | barGlyphs barTopC barTimeC barWidthC mapC |
  12993.     barGlyphs _ FreeVariable value: TracedCollection new.
  12994.     "Hardwired: yOrigin2 = 380, ySpacing = 4"
  12995.     barTopC _ Constraint
  12996.         names: #(key barTop)
  12997.         methods: #(
  12998.             'barTop _ 380 - 1 - (key * 4)'
  12999.             'key _ (380 - 1 - barTop) // 4').
  13000.     "Hardwired: xOrigin = 22"
  13001.     barTimeC _ Constraint
  13002.         names: #(time barLeft timeOrigin timeScale)
  13003.         methods: #(
  13004.             'barLeft _ ((time asFloat - timeOrigin) * timeScale) rounded + 22'
  13005.             'time _ ((barLeft - 22) // timeScale) + timeOrigin rounded').
  13006.     barWidthC _ Constraint
  13007.         names: #(duration barWidth timeScale)
  13008.         methods: #(
  13009.             'barWidth _ (duration asFloat * timeScale) rounded'
  13010.             'duration _ barWidth asFloat // timeScale').
  13011.  
  13012.     mapC _ (BijectiveMapConstraint new)
  13013.         fromSet: noteGlyphs toSet: barGlyphs
  13014.         fromClass: NoteGlyph toClass: NoteBarGlyph
  13015.         strength: #required.
  13016.     mapC addPairwiseConstraint: ((PairConstraintHolder new) 
  13017.         constraint: barTopC
  13018.         fromPath: #pitchVar toPath: #topVar
  13019.         strength: #required).
  13020.     mapC addPairwiseConstraint: ((PairConstraintHolder new) 
  13021.         constraint: barTimeC
  13022.         fromPath: #startVar toPath: #leftVar
  13023.         otherVars: (Array with: timeOrigin with: timeScale)
  13024.         strength: #required).
  13025.     mapC addPairwiseConstraint: ((PairConstraintHolder new) 
  13026.         constraint: barWidthC
  13027.         fromPath: #durationVar toPath: #widthVar
  13028.         otherVars: (Array with: timeScale)
  13029.         strength: #required).
  13030.     ^barGlyphs!
  13031. updateVisibleNotes
  13032.  
  13033.     | start end voice visible lastIndex lastStart |
  13034. Transcript show: 'filtering...'.
  13035.     start _ timeOrigin value rounded.
  13036.     end _ start + ((viewWidth value - 60) // timeScale value).
  13037.     voice _ visibleVoice value.
  13038.     visible _ OrderedCollection new: 100.
  13039.     theScore do:
  13040.         [: note |
  13041.          (((note start >= start) & ((note start + note duration) < end)) and:
  13042.           [(voice == 0) or: [note voice == voice]]) ifTrue:
  13043.             [visible add: note]].
  13044.     lastIndex _ lastStart _ -1.
  13045.     (visible asSortedCollection: [: n1 : n2 | n1 start <= n2 start]) do:
  13046.         [: note |
  13047.          (note start == lastStart)
  13048.             ifTrue: [note setIndex: lastIndex]
  13049.             ifFalse:
  13050.                 [note setIndex: (lastIndex _ lastIndex + 1).
  13051.                  lastStart _ note start]].
  13052.     self clearSelection.
  13053. Transcript show: 'Done ', visible size printString, ' notes'; cr.
  13054.     Cursor wait showWhile: [
  13055.         visibleNotes changeIn:
  13056.             [visibleNotes value updateContents: visible]].! !
  13057.  
  13058. Plus1Demo comment:
  13059. '                                ***** Why use Constraint Hierarchies? (Sums) *****
  13060.  
  13061. Constraint hierarchies are useful for many parts of a software system including: (i) as a declarative specification for defaults, (ii) as a mechanism to describe the behavior of a graphical user interface, and (iii) as a mechanism for declaratively controlling the dataflow.  Typically, to control the flow of data in a "flat" constraint system one must use some operational features.  For example, many constraint system use a well-defined search mechanism and thus the user can write his or her rules to take advantage of that mechanism to control the dataflow, i.e., he or she can use non-declarative features.  Of course, if the system is improved and the search algorithm changes, the program no longer works correctly.  One of the benefits of using a constraint hierarchy is that the hierarchy can control the dataflow declaratively.
  13062.  
  13063. The no-hierarchy demo has a flat constraint system and just a little experimentation will illustrate that its behavior is difficult to predict.  Specifically, the data does not flow from left-to-right as one might expect.  The hierarchy demo uses constraints of different strengths to cause the "correct" dataflow.  Furthermore, any constraint hierarchy solver will produce exactly the same solutions for this second demo, regardless of its implementation (assuming, of course, that the solver is implemented correctly.)
  13064. '!
  13065.  
  13066. !Plus1Demo methodsFor: 'initialize-release'!
  13067. create
  13068.     "Plus1Demo releaseConstraints"
  13069.  
  13070.     | texts xs ys ps |
  13071.     Transcript cr; show: 'Building the ' , self class name , '..'.
  13072.     Transcript cr; show: '..adding the components'.
  13073.     values _ Array new: 7.
  13074.     1 to: values size do: [:i | values at: i put: (FreeVariable value: 10)].
  13075.     texts _ Array new: values size.
  13076.     1 to: values size do: [:i | texts at: i put: BoxTextGlyph new].
  13077.     xs _ #(50 50 150 150 250 250 350 ).
  13078.     ys _ #(50 150 100 200 150 250 200 ).
  13079.     ps _ OrderedCollection new.
  13080.     xs with: ys do: [:x :y | ps add: x @ y].
  13081.     texts with: ps do: 
  13082.         [:text :p | 
  13083.         text moveTo: p].
  13084.     xs _ #(100 200 300 ).
  13085.     ys _ #(100 150 200 ).
  13086.     1
  13087.         to: 5
  13088.         by: 2
  13089.         do: 
  13090.             [:i | 
  13091.             p _ ThreeProngTextGlyph new initialize.
  13092.             p
  13093.                 left: (texts at: i) center
  13094.                 right: (texts at: i + 2) center
  13095.                 down: (texts at: i + 1) center
  13096.                 string: '+'.
  13097.             self addGlyph: p].
  13098.     texts do: [:each | self addGlyph: each].
  13099.     Transcript cr; show: '..adding the consistency constraints'.
  13100.     PrintConstraint isNil ifTrue: [PrintConstraint _ Constraint names: #(text temp ) methods: #('temp _ text asNumber' 'text _ temp printString' )].
  13101.     texts with: values do: [:text :value | PrintConstraint copy
  13102.             var: text textVar
  13103.             var: value
  13104.             strength: #required].
  13105.     PlusConstraint isNil ifTrue: [PlusConstraint _ Constraint names: #(a b c ) methods: #('c _ a + b' 'a _ c - b' 'b _ c - a' )].
  13106.     1
  13107.         to: 5
  13108.         by: 2
  13109.         do: [:i | PlusConstraint copy
  13110.                 var: (values at: i)
  13111.                 var: (values at: i + 1)
  13112.                 var: (values at: i + 2)
  13113.                 strength: #required].
  13114.     self createDefaults.
  13115.     Transcript cr; show: 'finished'!
  13116. createDefaults!
  13117. initialize
  13118.     super initialize.
  13119.     self create! !
  13120.  
  13121. !Plus1Demo methodsFor: 'public'!
  13122. open
  13123.     "Plus1Demo new open"
  13124.  
  13125.     | topView |
  13126.     topView _ SpecialSystemView
  13127.                 model: nil
  13128.                 label: 'Plus Demo, No Hierarchy'
  13129.                 minimumSize: 400 @ 300.
  13130.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  13131.     topView controller open! !
  13132.  
  13133. !Plus2Demo methodsFor: 'initialize-release'!
  13134. createDefaults
  13135.     | ss |
  13136.     ss _ #(3 3 4 4 5 5 6 ).
  13137.     values with: ss do: [:each :s | StayConstraint new var: each primstrength: (Strength new initializeWith: 'special' , s printString and: s)]! !
  13138.  
  13139. !Plus2Demo methodsFor: 'public'!
  13140. open
  13141.     "Plus2Demo new open"
  13142.  
  13143.     | topView |
  13144.     topView _ SpecialSystemView
  13145.                 model: nil
  13146.                 label: 'Plus Demo With Hierarchy'
  13147.                 minimumSize: 400 @ 300.
  13148.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  13149.     topView controller open! !
  13150.  
  13151. !ScoreOverview methodsFor: 'all'!
  13152. addTitle: aString
  13153.  
  13154.     | title |
  13155.     title _ TextGlyph new
  13156.         text: aString; font: (TextStyle default fontAt: 5);
  13157.         moveTo: 0@25.
  13158.     (Constraint names: #(center width) methods: #('center _ width // 2'))
  13159.         var: title box center xVar var: viewWidth strength: #default.
  13160.     self addGlyph: title.!
  13161. makeStavesCount: n scale: timeScale
  13162.  
  13163.     | staffPlace staff |
  13164.     staves do: [: g | self removeGlyph: g].
  13165.     staves _ OrderedCollection new.
  13166.     staffPlace _ 20@60.
  13167.     1 to: n do:
  13168.         [: i |
  13169.          staff _ GrandStaffGlyph new.
  13170.          OffsetConstraint from: (staff widthVar) to: viewWidth require: 41.
  13171.          staff score: score.
  13172.          staff staffIndex: i - 1.
  13173.          staff timeScale: timeScale.
  13174.          staff moveTo: staffPlace.
  13175.          staves add: staff.
  13176.          self addGlyph: staff.
  13177.          staffPlace _ staffPlace + (0@72)].!
  13178. noteAt: start dur: duration pitch: pitch vel: velocity voice: voice
  13179.  
  13180.     | note keyAndMod |
  13181.     note _ NoteGlyph new.
  13182.     note start: start.
  13183.     note duration: duration.
  13184.     keyAndMod _ NoteGlyph pitchToKeyAndMod: pitch.
  13185.     note pitch: keyAndMod first.
  13186.     note modifier: keyAndMod last.
  13187.     note velocity: velocity.
  13188.     note voice: voice.
  13189.     ^note!
  13190. openOn: adagioScore title: titleString
  13191.     "ScoreOverview new openOn: ('c; d; e; f; g' asScore) title: 'Test Score'"
  13192.     "ScoreOverview new openOn: (Score fromFile: 'bach.gio') title: 'Bach Fugue'"
  13193.  
  13194.     super initialize.
  13195.     score _ OrderedCollection new.
  13196.     staves _  OrderedCollection new.
  13197.     viewWidth value: 300.        "just an initial value to get started"
  13198.     adagioScore do:
  13199.         [: note |
  13200.          score add: (self
  13201.             noteAt: note time
  13202.             dur: note dur
  13203.             pitch: note pitch
  13204.             vel: note velocity
  13205.             voice: note voice)].
  13206.     self makeStavesCount: 6 scale: 3.
  13207.     self addTitle: titleString.
  13208.     SceneView openOn: self.! !
  13209.  
  13210. CFKDemo comment:
  13211. '                        ***** Introducing Constraints (Celsius-Fahrenheit-Kelvin) *****
  13212.  
  13213. Just as a database demo is not complete with the Employee relation and a graphics demo is not complete without rendering a teapot, a constraint demo is not complete with the Celsius-Fahrenheit example.
  13214.  
  13215. Constraints are multi-directional, automatically-maintained assertions about the state of a system.  For example, the relation between Celsius and Fahrenheit temperatures is a constraint.  Constraints are often stated as equations, but other mechanism are both possible and are used in these demos.
  13216.  
  13217. This demo uses many different types of constraints: arithmetic constraints to maintain the relation between the different interpretations of temperature; layout constraints to keep the title under each thermometer, the equations between the thermometers, and the number beside the mercury; and consistency constraints to keep the mercury height proportional to the temperature which in turn is equal to the text printed beside it.  Last, but not least, special graphical constraints are used to control the display when the temperature gets too cold or too hot (Try 10 Kelvin or 200 Celsius!!).  Yes, the entire demo is composed of many smaller objects working together, synchronized and kept consistent with constraints.
  13218.  
  13219. Interesting actions to try are: (1) moving the mercury up and down, (2) selecting and then entering a temperature directly (use <delete> and the number keys), (3) switching to "edit" mode and rearranging the thermometers (press the mouse button on the title bar to get a menu which includes "edit".  Use the same menu to return to "operate").
  13220. '!
  13221.  
  13222. !CFKDemo methodsFor: 'initialize-release'!
  13223. create
  13224.     | c f k c1 tc tf tk tcf tck mpc |
  13225.     Transcript cr; show: 'Building the ', self class name, '..'.
  13226.     Transcript cr; show: '..adding the Fahrenheit thermometer'.
  13227.     f _ ThermometerGlyph new initialize.
  13228.     f moveTo: 50 @ 160.
  13229.     f overVal: 752.0 underVal: -184.0.
  13230.     self addGlyph: f.
  13231.     Transcript cr; show: '..adding the Celsius thermometer'.
  13232.     c _ ThermometerGlyph new initialize.
  13233.     c moveTo: 250 @ 160.
  13234.     c overVal: 400.0 underVal: -120.0.
  13235.     self addGlyph: c.
  13236.     Transcript cr; show: '..adding the Kelvin thermometer'.
  13237.     k _ ThermometerGlyph new initialize.
  13238.     k moveTo: 450 @ 160.
  13239.     k minVal: 0.
  13240.     k maxVal: 400.
  13241.     k overVal: 450.0 underVal: -1.0.
  13242.     self addGlyph: k.
  13243.     Transcript cr; show: '..adding the consistency constraints'.
  13244.     c1 _ Constraint names: #(c f ) methods: #('c _ (f - 32.0) / 1.8' 'f _ (c * 1.8) + 32' ).
  13245.     c1
  13246.         var: c temperatureVar
  13247.         var: f temperatureVar
  13248.         strength: #required.
  13249.     c1 _ Constraint names: #(c k ) methods: #('c _ k - 273.16' 'k _ c + 273.16' ).
  13250.     c1
  13251.         var: c temperatureVar
  13252.         var: k temperatureVar
  13253.         strength: #required.
  13254.     Transcript cr; show: '..adding the text boxes'.
  13255.     tc _ TextGlyph new initialize.
  13256.     tc text: 'Celsius'.
  13257.     self addGlyph: tc.
  13258.     tf _ TextGlyph new initialize.
  13259.     tf text: 'Fahrenheit'.
  13260.     self addGlyph: tf.
  13261.     tk _ TextGlyph new initialize.
  13262.     tk text: 'Kelvin'.
  13263.     self addGlyph: tk.
  13264.     tcf _ TwoProngTextGlyph new initialize.
  13265.     tcf moveTo: 150 @ 325.
  13266.     tcf
  13267.         left: f editBox rightVar @ f editBox bottomVar
  13268.         right: c editBox leftVar @ c editBox bottomVar
  13269.         string: 'c * 1.8 = f - 32'.
  13270.     self addGlyph: tcf.
  13271.     tck _ TwoProngTextGlyph new initialize.
  13272.     tck moveTo: 350 @ 325.
  13273.     tck
  13274.         left: c editBox rightVar @ c editBox bottomVar
  13275.         right: k editBox leftVar @ k editBox bottomVar
  13276.         string: 'k = c + 273.16'.
  13277.     self addGlyph: tck.
  13278.     Transcript cr; show: '..adding the layout constraints'.
  13279.     EqualityConstraint
  13280.         var: c editBox center xVar
  13281.         var: tc box center xVar
  13282.         strength: #required.
  13283.     OffsetConstraint
  13284.         from: c editBox bottomVar
  13285.         to: tc box topVar
  13286.         require: 30.
  13287.     EqualityConstraint
  13288.         var: f editBox center xVar
  13289.         var: tf box center xVar
  13290.         strength: #required.
  13291.     OffsetConstraint
  13292.         from: f editBox bottomVar
  13293.         to: tf box topVar
  13294.         require: 30.
  13295.     EqualityConstraint
  13296.         var: k editBox center xVar
  13297.         var: tk box center xVar
  13298.         strength: #required.
  13299.     OffsetConstraint
  13300.         from: k editBox bottomVar
  13301.         to: tk box topVar
  13302.         require: 30.
  13303.     Transcript cr; show: 'finished'!
  13304. create1
  13305.     | c f k c1 |
  13306.     c _ ThermometerGlyph new initialize.
  13307.     c moveTo: 30 @ 160.
  13308.     f _ ThermometerGlyph new initialize.
  13309.     f moveTo: 90 @ 160.
  13310.     k _ ThermometerGlyph new initialize.
  13311.     k moveTo: 150 @ 160.
  13312.     k minVal: 0.
  13313.     k maxVal: 400.
  13314.     self addGlyph: c; addGlyph: f; addGlyph: k.
  13315.     c1 _ Constraint names: #(c f ) methods: #('c _ (f - 32.0) / 1.8' 'f _ (c * 1.8) + 32' ).
  13316.     c1
  13317.         var: c temperatureVar
  13318.         var: f temperatureVar
  13319.         strength: #required.
  13320.     c1 _ Constraint names: #(c k ) methods: #('c _ k - 273.16' 'k _ c + 273.16' ).
  13321.     c1
  13322.         var: c temperatureVar
  13323.         var: k temperatureVar
  13324.         strength: #required!
  13325. create2
  13326.     | c f k c1 tc tf tk tcf tck mpc |
  13327.     Transcript cr; show: 'Building the CFKDemo..'.
  13328.     Transcript cr; show: '..adding the Fahrenheit thermometer'.
  13329.     f _ ThermometerGlyph new initialize.
  13330.     f moveTo: 50 @ 160.
  13331.     self addGlyph: f.
  13332.     Transcript cr; show: '..adding the Celsius thermometer'.
  13333.     c _ ThermometerGlyph new initialize.
  13334.     c moveTo: 250 @ 160.
  13335.     self addGlyph: c.
  13336.     Transcript cr; show: '..adding the Kelvin thermometer'.
  13337.     k _ ThermometerGlyph new initialize.
  13338.     k moveTo: 450 @ 160.
  13339.     k minVal: 0.
  13340.     k maxVal: 400.
  13341.     self addGlyph: k.
  13342.     Transcript cr; show: '..adding the consistency constraints'.
  13343.     c1 _ Constraint names: #(c f ) methods: #('c _ (f - 32.0) / 1.8' 'f _ (c * 1.8) + 32' ).
  13344.     c1
  13345.         var: c temperatureVar
  13346.         var: f temperatureVar
  13347.         strength: #required.
  13348.     c1 _ Constraint names: #(c k ) methods: #('c _ k - 273.16' 'k _ c + 273.16' ).
  13349.     c1
  13350.         var: c temperatureVar
  13351.         var: k temperatureVar
  13352.         strength: #required.
  13353.     Transcript cr; show: '..adding the text boxes'.
  13354.     tc _ TextGlyph new initialize.
  13355.     tc text: 'Celsius'.
  13356.     self addGlyph: tc.
  13357.     tf _ TextGlyph new initialize.
  13358.     tf text: 'Fahrenheit'.
  13359.     self addGlyph: tf.
  13360.     tk _ TextGlyph new initialize.
  13361.     tk text: 'Kelvin'.
  13362.     self addGlyph: tk.
  13363.     tcf _ TextGlyph new initialize.
  13364.     tcf text: 'c * 1.8 = f - 32'.
  13365.     tcf moveTo: 150@160.
  13366.     self addGlyph: tcf.
  13367.     tck _ TextGlyph new initialize.
  13368.     tck text: 'k = c + 273.16'.
  13369.     tck moveTo: 350@160.
  13370.     self addGlyph: tck.
  13371.     Transcript cr; show: '..adding the layout constraints'.
  13372.     EqualityConstraint
  13373.         var: c editBox center xVar
  13374.         var: tc box center xVar
  13375.         strength: #required.
  13376.     OffsetConstraint
  13377.         from: c editBox bottomVar
  13378.         to: tc box topVar
  13379.         require: 30.
  13380.     EqualityConstraint
  13381.         var: f editBox center xVar
  13382.         var: tf box center xVar
  13383.         strength: #required.
  13384.     OffsetConstraint
  13385.         from: f editBox bottomVar
  13386.         to: tf box topVar
  13387.         require: 30.
  13388.     EqualityConstraint
  13389.         var: k editBox center xVar
  13390.         var: tk box center xVar
  13391.         strength: #required.
  13392.     OffsetConstraint
  13393.         from: k editBox bottomVar
  13394.         to: tk box topVar
  13395.         require: 30.
  13396.     mpc _ Constraint names: #(p1 mp p2 ) methods: #('mp _ (p1 + p2) / 2' 'p1 _ mp*2 - p2' 'p2 _ mp*2 - p1' ).
  13397.     mpc copy
  13398.         var: c editBox bottomVar
  13399.         var: tcf box bottomVar
  13400.         var: f editBox bottomVar
  13401.         strength: #required.
  13402.     mpc copy
  13403.         var: c editBox leftVar
  13404.         var: tcf box leftVar
  13405.         var: f editBox leftVar
  13406.         strength: #required.
  13407.     mpc copy
  13408.         var: c editBox bottomVar
  13409.         var: tck box bottomVar
  13410.         var: k editBox bottomVar
  13411.         strength: #required.
  13412.     mpc copy
  13413.         var: c editBox leftVar
  13414.         var: tck box leftVar
  13415.         var: k editBox leftVar
  13416.         strength: #required.
  13417.     StayConstraint var: c editBox leftVar strength: #default.
  13418.     StayConstraint var: f editBox leftVar strength: #default.
  13419.     StayConstraint var: k editBox leftVar strength: #default.
  13420.     StayConstraint var: c editBox bottomVar strength: #default.
  13421.     StayConstraint var: f editBox bottomVar strength: #default.
  13422.     StayConstraint var: k editBox bottomVar strength: #default.
  13423.     Transcript cr; show: 'finished'!
  13424. create3
  13425.     | c f k c1 tc tf tk tcf tck mpc |
  13426.     Transcript cr; show: 'Building the CFKDemo..'.
  13427.     Transcript cr; show: '..adding the Fahrenheit thermometer'.
  13428.     f _ ThermometerGlyph new initialize.
  13429.     f moveTo: 50 @ 160.
  13430.     self addGlyph: f.
  13431.     Transcript cr; show: '..adding the Celsius thermometer'.
  13432.     c _ ThermometerGlyph new initialize.
  13433.     c moveTo: 250 @ 160.
  13434.     self addGlyph: c.
  13435.     Transcript cr; show: '..adding the Kelvin thermometer'.
  13436.     k _ ThermometerGlyph new initialize.
  13437.     k moveTo: 450 @ 160.
  13438.     k minVal: 0.
  13439.     k maxVal: 400.
  13440.     self addGlyph: k.
  13441.     Transcript cr; show: '..adding the consistency constraints'.
  13442.     c1 _ Constraint names: #(c f ) methods: #('c _ (f - 32.0) / 1.8' 'f _ (c * 1.8) + 32' ).
  13443.     c1
  13444.         var: c temperatureVar
  13445.         var: f temperatureVar
  13446.         strength: #required.
  13447.     c1 _ Constraint names: #(c k ) methods: #('c _ k - 273.16' 'k _ c + 273.16' ).
  13448.     c1
  13449.         var: c temperatureVar
  13450.         var: k temperatureVar
  13451.         strength: #required.
  13452.     Transcript cr; show: '..adding the text boxes'.
  13453.     tc _ TextGlyph new initialize.
  13454.     tc text: 'Celsius'.
  13455.     self addGlyph: tc.
  13456.     tf _ TextGlyph new initialize.
  13457.     tf text: 'Fahrenheit'.
  13458.     self addGlyph: tf.
  13459.     tk _ TextGlyph new initialize.
  13460.     tk text: 'Kelvin'.
  13461.     self addGlyph: tk.
  13462.     tcf _ TextGlyph new initialize.
  13463.     tcf text: 'c * 1.8 = f - 32'.
  13464.     tcf moveTo: 150@260.
  13465.     self addGlyph: tcf.
  13466.     tck _ TextGlyph new initialize.
  13467.     tck text: 'k = c + 273.16'.
  13468.     tck moveTo: 350@260.
  13469.     self addGlyph: tck.
  13470.     Transcript cr; show: '..adding the layout constraints'.
  13471.     EqualityConstraint
  13472.         var: c editBox center xVar
  13473.         var: tc box center xVar
  13474.         strength: #required.
  13475.     OffsetConstraint
  13476.         from: c editBox bottomVar
  13477.         to: tc box topVar
  13478.         require: 30.
  13479.     EqualityConstraint
  13480.         var: f editBox center xVar
  13481.         var: tf box center xVar
  13482.         strength: #required.
  13483.     OffsetConstraint
  13484.         from: f editBox bottomVar
  13485.         to: tf box topVar
  13486.         require: 30.
  13487.     EqualityConstraint
  13488.         var: k editBox center xVar
  13489.         var: tk box center xVar
  13490.         strength: #required.
  13491.     OffsetConstraint
  13492.         from: k editBox bottomVar
  13493.         to: tk box topVar
  13494.         require: 30.
  13495.     StayConstraint var: c editBox leftVar strength: #default.
  13496.     StayConstraint var: f editBox leftVar strength: #default.
  13497.     StayConstraint var: k editBox leftVar strength: #default.
  13498.     StayConstraint var: c editBox bottomVar strength: #default.
  13499.     StayConstraint var: f editBox bottomVar strength: #default.
  13500.     StayConstraint var: k editBox bottomVar strength: #default.
  13501.     mpc _ Constraint names: #(p1 mp p2 ) methods: #('mp _ (p1 + p2) / 2' 'p1 _ mp*2 - p2' 'p2 _ mp*2 - p1' ).
  13502.     mpc copy
  13503.         var: c editBox bottomVar
  13504.         var: tcf box bottomVar
  13505.         var: f editBox bottomVar
  13506.         strength: #required.
  13507.     mpc copy
  13508.         var: c editBox leftVar
  13509.         var: tcf box leftVar
  13510.         var: f editBox leftVar
  13511.         strength: #required.
  13512.     mpc copy
  13513.         var: c editBox bottomVar
  13514.         var: tck box bottomVar
  13515.         var: k editBox bottomVar
  13516.         strength: #required.
  13517.     mpc copy
  13518.         var: c editBox leftVar
  13519.         var: tck box leftVar
  13520.         var: k editBox leftVar
  13521.         strength: #required.
  13522.     Transcript cr; show: 'finished'!
  13523. initialize
  13524.     super initialize.
  13525.     self create! !
  13526.  
  13527. !CFKDemo methodsFor: 'public'!
  13528. open
  13529.     "CFKDemo new open"
  13530.  
  13531.     | topView |
  13532.     topView _ SpecialSystemView
  13533.                 model: nil
  13534.                 label: 'Fahrenheit - Celsius - Kelvin Demo'
  13535.                 minimumSize: 525 @ 400.
  13536.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  13537.     topView controller open! !
  13538.  
  13539. SplittingDemo comment:
  13540. '                            ***** Constraint on Objects (Multi-User Application) *****
  13541.  
  13542. These demos illustrate two features of constraint systems: (one) constraints can be useful in the development of today''s multi-user, multi-media, multi-buzzword applications, and (two) constraints on complex objects can be implemented in a number of ways.  These demos illustrate two mechanisms: splitting (decomposing a constraint on a whole object into separate constraints on each of its parts) and raising (moving constraints on an object''s parts "up" to become constraints on the whole object).  Numerous other mechanisms also exist.
  13543.  
  13544. In these examples, we assume a two-user, two-mouse interactive graphical editor.  Here, however, the second user is simulated by the computer.  Note that even while the second user is busy editting her objects, the first user (you) can still edit yours.  Again, this is because all interactions are implemented with constraints and the system can solve many constraints just as easily as it can solve a few.
  13545.  
  13546. Each of these demos has a horizontal line and a vertical line.  The first user (you) are supposed to drag the right end of the horizontal line and the second user to drag the bottom end of the vertical line.  This works well in the splitting demo.  In the raising demo, however, the system has raised the constraints too far and has removed precious degrees of freedom from the objects.  Thus the constraints (you, the second user, horizontal, vertical) cannot all be solved simultaneously.
  13547. '!
  13548.  
  13549. !SplittingDemo methodsFor: 'initialize-release'!
  13550. create
  13551.     | hl vl m c |
  13552.     Transcript cr; show: 'Building the ' , self class name , '..'.
  13553.     Transcript cr; show: '..adding the components'.
  13554.     m _ FakeMouseGlyph new initialize.
  13555.     hl _ LineGlyph new.
  13556.     hl moveTo: 100 @ 100.
  13557.     vl _ LineGlyph new.
  13558.     vl moveTo: 100 @ 150.
  13559.     self addGlyph: m; addGlyph: hl; addGlyph: vl.
  13560.     Transcript cr; show: '..adding the consistency constraints'.
  13561.     EqualityConstraint
  13562.         var: hl p1 yVar
  13563.         var: hl p2 yVar
  13564.         strength: #required.
  13565.     EqualityConstraint
  13566.         var: vl p1 xVar
  13567.         var: vl p2 xVar
  13568.         strength: #required.
  13569.     EqualityConstraint
  13570.         var: hl p1 yVar
  13571.         var: vl p1 yVar
  13572.         strength: #required.
  13573.     EqualityConstraint
  13574.         var: hl p1 xVar
  13575.         var: vl p1 xVar
  13576.         strength: #required.
  13577.     EqualityConstraint
  13578.         var: vl p2 xVar
  13579.         var: m xVar
  13580.         strength: #required.
  13581.     EqualityConstraint
  13582.         var: vl p2 yVar
  13583.         var: m yVar
  13584.         strength: #required.
  13585.     "c _ Constraint names: #(new old ) methods: #('new _ ((old + SplittingDemo nextRandom) min: 350) max: 5' ).
  13586.     fakemouse _ Array with: (c copy
  13587.                     var: m xVar
  13588.                     var: m xVar last
  13589.                     strength: #default)
  13590.                 with: (c copy
  13591.                         var: m yVar
  13592.                         var: m yVar last
  13593.                         strength: #default)."
  13594.     fakemouse _ Array new: 2.
  13595.     fakemouse at: 1 put: ((Constraint
  13596.         names: #(new old )
  13597.         methods: #('new _ SplittingDemo nextRandomX' ))
  13598.             var: m xVar
  13599.             var: m xVar last
  13600.             strength: #default).
  13601.     fakemouse at: 2 put: ((Constraint
  13602.         names: #(new old )
  13603.         methods: #('new _ SplittingDemo nextRandomY' ))
  13604.             var: m yVar
  13605.             var: m yVar last
  13606.             strength: #default).
  13607.     Transcript cr; show: 'finished'!
  13608. initialize
  13609.     super initialize.
  13610.     self create! !
  13611.  
  13612. !SplittingDemo methodsFor: 'public'!
  13613. open
  13614.     "SplittingDemo new open"
  13615.  
  13616.     | topView |
  13617.     topView _ SpecialSystemView
  13618.                 model: nil
  13619.                 label: 'Splitting'
  13620.                 minimumSize: 400 @ 400.
  13621.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  13622.     topView controller open! !
  13623.  
  13624. !SplittingDemo methodsFor: 'testing'!
  13625. isAnimated
  13626.     ^true! !
  13627.  
  13628. !SplittingDemo methodsFor: 'background processing'!
  13629. computeBackgroundPlan
  13630.     ^Planner extractPlanFromInputConstraints: fakemouse!
  13631. initialAnimationConstraints
  13632.     ^fakemouse! !
  13633.  
  13634. AnchorLine1Demo comment:
  13635. '                                        ***** What is a Constraint Hierarchy? (Anchors and Mice) *****
  13636.  
  13637. A constraint hierarchy is an ordered sequence of sets of constraints such that the constraints in the stronger sets dominate those in the weaker sets.  For example, if "X = 5" is strong and "X = 3" is weak, the solution would be "X = 5".  The strongest set in a constraint hierarchy is the required level: these constraints must be satisified.  All other levels are preferred and should be satisfied (respecting their various strengths) may be violated if necessary.
  13638.  
  13639. These three examples demonstrate different constraint hierarchies.  In the no-anchor example, the only constraints are the "horizontal line" constraint and (when the mouse drags a point) the "mouse drags point" constraint.  (Note: all interactions are implemented using constraints, thus the connection between the mouse and the point it is dragging is actually a constraint.)  In the anchor example, there is a strong "anchor" constraint which holds the left point in place.  This anchor constraint is stronger than the mouse constraint, and thus the mouse cannot move the left end and it can only move the right end back and forth.  In the anchor-strong-mouse example, the mouse has been made stronger than the anchor and thus the mouse can drag the anchor around again.
  13640.  
  13641. To summarize, the three examples have the following constraint hierarchies:
  13642.         * no-anchor *                                * anchor *                                * anchor-strong-mouse *
  13643.     required horizontal line                        required horizontal line                        required horizontal line
  13644.     medium mouse                                strong anchor                                veryStrong mouse
  13645.                                                 medium mouse                                strong anchor
  13646. '!
  13647.  
  13648. !AnchorLine1Demo methodsFor: 'initialize-release'!
  13649. create
  13650.     | l |
  13651.     Transcript cr; show: 'Building the ' , self class name , '..'.
  13652.     Transcript cr; show: '..adding the components'.
  13653.     l _ LineGlyph new.
  13654.     l moveTo: 100 @ 100.
  13655.     self addGlyph: l.
  13656.     Transcript cr; show: '..adding the consistency constraints'.
  13657.     EqualityConstraint
  13658.         var: l p1 yVar
  13659.         var: l p2 yVar
  13660.         strength: #required.
  13661.     Transcript cr; show: 'finished'!
  13662. initialize
  13663.     super initialize.
  13664.     self create! !
  13665.  
  13666. !AnchorLine1Demo methodsFor: 'public'!
  13667. open
  13668.     "AnchorLine1Demo new open"
  13669.  
  13670.     | topView |
  13671.     topView _ SpecialSystemView
  13672.                 model: nil
  13673.                 label: 'Horizontal Line, No Anchor'
  13674.                 minimumSize: 300 @ 200.
  13675.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  13676.     topView controller open! !
  13677.  
  13678. !SpringDemo methodsFor: 'public'!
  13679. openDemo
  13680.     "SpringDemo new openDemo"
  13681.  
  13682.     super initialize.
  13683.     self addGlyph: (TextButtonGlyph new
  13684.         text: 'Run'; moveTo: 27@22;
  13685.         script: 'model run: view').
  13686.     self addGlyph: (TextButtonGlyph new
  13687.         text: 'Stop'; moveTo: 62@22;
  13688.         script: 'model stop: view').
  13689.     self addGlyph: (TextButtonGlyph new
  13690.         text: 'Anchor'; moveTo: 125@22;
  13691.         script: 'view controller addAndPlace: AnchorGlyph new').
  13692.     self addGlyph: (TextButtonGlyph new
  13693.         text: 'Vector'; moveTo: 177@22;
  13694.         script: 'view controller addAndPlace: VectorGlyph new').
  13695.     self addGlyph: (TextButtonGlyph new
  13696.         text: 'Spring'; moveTo: 227@22;
  13697.         script: 'view controller addAndPlace: SpringGlyph new').
  13698.  
  13699.     speed _ FreeVariable value: 0.062.
  13700. "    self addGlyph: (TextGlyph new
  13701.         text: 'Speed:'; moveTo: (31@52)).
  13702.     self addGlyph: ((HSliderGlyph on: speed)
  13703.         minVal: 0.0; maxVal: 0.5; value: 0.06;
  13704.         moveTo: 121@52)."
  13705.  
  13706.     SceneView openOn: self.! !
  13707.  
  13708. !SpringDemo methodsFor: 'simulation execution'!
  13709. backgroundTask: view
  13710.  
  13711.     (planToRun == nil) ifFalse:
  13712.         [planToRun execute.
  13713.          view displayFeedback].!
  13714. run: view
  13715.     "Install the simulation constraints that cause nodes to move according to the forces applied to them. Record a plan to execute continuously. The simulation can be stopped by registering a nil plan."
  13716.  
  13717.     self addSimulationConstraints.
  13718.     planToRun _ Planner extractPlanFromVariables: (Array with: speed).
  13719.     view computeBackground.!
  13720. stop: view
  13721.  
  13722.     planToRun _ nil.
  13723.     self removeSimulationConstraints.
  13724.     view computeEnclosingRectangle.
  13725.     view displayScene.! !
  13726.  
  13727. !SpringDemo methodsFor: 'simulation constraints'!
  13728. addAnchor: anchor to: clusterDict
  13729.     "Register an anchor glyph in the cluster dictionary."
  13730.  
  13731.     | entry |
  13732.     self removeForceConstraintsOn: (anchor node).
  13733.     entry _ clusterDict at: (anchor node label) ifAbsent: [SpringNodeCluster new].
  13734.     entry addAnchor: anchor.
  13735.     clusterDict at: (anchor node label) put: entry.!
  13736. addForceConstraintOn: cluster
  13737.     "Install force constraints on the given cluster."
  13738.  
  13739.     | node |
  13740.     (xMoveC == nil) ifTrue:
  13741.         [xMoveC _ Constraint
  13742.             names: #(newX oldX speed forceVector)
  13743.             methods: #('newX _ oldX + (speed * forceVector x)')].
  13744.     (yMoveC == nil) ifTrue:
  13745.         [yMoveC _ Constraint
  13746.             names: #(newY oldY speed forceVector)
  13747.             methods: #('newY _ oldY + (speed * forceVector y)')].
  13748.     node _ cluster node.
  13749.     (ClusterSumConstraint new)
  13750.         cluster: (cluster) forceVar: (node forceVar)
  13751.         strength: #required.
  13752.     (xMoveC copy)
  13753.         var: (node xVar) var: (node xVar last)
  13754.         var: (speed) var: (node forceVar)
  13755.         strength: #default.
  13756.     (yMoveC copy)
  13757.         var: (node yVar) var: (node yVar last)
  13758.         var: (speed) var: (node forceVar)
  13759.         strength: #default.!
  13760. addSimulationConstraints
  13761.     "Add simulation constraints to:
  13762.         1. compute the combined force on a node, and
  13763.         2. update the node position according to the current force."
  13764.  
  13765.     | i newClusters |
  13766.     "first, mark all nodes; merged nodes will end up with the same marks"
  13767.     i _ 1.
  13768.     (glyphs value) do:
  13769.         [: g |
  13770.          (g class == SpringGlyph) ifTrue:
  13771.             [g p1 label: (i _ i + 1).    
  13772.              g p2 label: (i _ i + 1)].
  13773.          (g class == VectorGlyph) ifTrue:
  13774.             [g p1 label: (i _ i + 1)].
  13775.          (g class == AnchorGlyph) ifTrue:
  13776.             [g node label: (i _ i + 1)]].
  13777.  
  13778.     "then, build dictionary of clusters"
  13779.     newClusters _ Dictionary new.
  13780.     (glyphs value) do:
  13781.         [: g |
  13782.          (g class == SpringGlyph) ifTrue:
  13783.             [self addSpring: g to: newClusters].
  13784.          (g class == VectorGlyph) ifTrue:
  13785.             [self addVector: g to: newClusters].
  13786.          (g class == AnchorGlyph) ifTrue:
  13787.             [self addAnchor: g to: newClusters]].
  13788.  
  13789.     "finally, add constraints for each cluster"
  13790.     newClusters do:
  13791.         [: cluster |
  13792.          (cluster anchored) ifFalse:
  13793.             [self addForceConstraintOn: cluster]].!
  13794. addSpring: rod to: clusterDict
  13795.     "Register a spring glyph in the cluster dictionary."
  13796.  
  13797.     | entry |
  13798.     self removeForceConstraintsOn: (rod p1).
  13799.     entry _ clusterDict at: (rod p1 label) ifAbsent: [SpringNodeCluster new].
  13800.     entry addP1InSpring: rod.
  13801.     clusterDict at: (rod p1 label) put: entry.
  13802.  
  13803.     self removeForceConstraintsOn: (rod p2).
  13804.     entry _ clusterDict at: (rod p2 label) ifAbsent: [SpringNodeCluster new].
  13805.     entry addP2InSpring: rod.
  13806.     clusterDict at: (rod p2 label) put: entry.!
  13807. addVector: vector to: clusterDict
  13808.     "Register a force vector glyph in the cluster dictionary."
  13809.  
  13810.     | entry |
  13811.     self removeForceConstraintsOn: (vector p1).
  13812.     entry _ clusterDict at: (vector p1 label) ifAbsent: [SpringNodeCluster new].
  13813.     entry addVector: vector.
  13814.     clusterDict at: (vector p1 label) put: entry.!
  13815. removeForceConstraintsOn: aSpringNode
  13816.  
  13817.     | forceVar |
  13818.     forceVar _ aSpringNode forceVar.
  13819.     (forceVar class == FreeVariable) ifTrue: [^self].
  13820.     forceVar constraints do:
  13821.         [: c | c destroyConstraint].!
  13822. removeSimulationConstraints
  13823.     "Remove all simulation constraints."
  13824.  
  13825.     (glyphs value) do:
  13826.         [: g |
  13827.          (g class == SpringGlyph) ifTrue:
  13828.             [self removeForceConstraintsOn: g p1.    
  13829.              self removeForceConstraintsOn: g p2].
  13830.          (g class == VectorGlyph) ifTrue:
  13831.             [self removeForceConstraintsOn: g p1].
  13832.          (g class == AnchorGlyph) ifTrue:
  13833.             [self removeForceConstraintsOn: g node]].! !
  13834.  
  13835. ThreePlanetDemo comment:
  13836. '                            ***** Animation (Orbiting Planetoids) *****
  13837.  
  13838. Constraints are especially useful for two aspects of graphics: static layout and dynamic behavior.  Constraints can be used to declaratively specify the layout of various graphical objects to ensure that positioning and other relations are maintained.  Perhaps more interesting, though, is the use of constraints to define dynamic behavior, e.g., animations.  Constraints are a natural mechanism for describing physical laws (even imaginary "Wiley E. Coyote" ones).  
  13839.  
  13840. These two demos illustrate the use of simple animation constraints.  In the fake-gravity demo, the slides control the orbit radius of the two planets and simple computation is used to find the next position of each planet.  Interestingly enough, the animation can continue while the user is interacting with the system---after all, the user''s interaction is implemented by constraints and the animation is implemented by constraints, thus the system can automatically solve the two sets together.  Thus the user can move the slider while the planets orbit.  However, the user can also grab any planet and drag it around and the other planets will continue their orbits, although now centered on the user''s planet.  This "re-centering" is because the user''s interaction constraint is stronger than the rest.
  13841.  
  13842. In the real-gravity demo, the slider control gravity and the four vectors illustrate the acceleration and velocity of the two planets.  All of the constraints are multi-directional, thus if the planets are dragged around, the vectors will indicate the velocity and acceleration of the mouse!!  And, if the velocity vector is dragged around, the acceleration and planet motion will match, and so on.  Unfortunately, it is very difficult to get the planets to orbit (or to do anything at all) which is why the fake-gravity demo is also supplied.
  13843. '!
  13844.  
  13845. !ThreePlanetDemo methodsFor: 'initialize-release'!
  13846. create
  13847.     | p1 p2 p3 h1 h2 c2 c3 |
  13848.     Transcript cr; show: 'Building the ', self class name, '..'.
  13849.     theta1 _ FreeVariable value: 0.0.
  13850.     r1 _ FreeVariable value: 100.0.
  13851.     theta2 _ FreeVariable value: 0.0.
  13852.     r2 _ FreeVariable value: 40.0.
  13853.     Transcript cr; show: '..adding planets'.
  13854.     p1 _ PlanetGlyph new initialize.
  13855.     p1 form1.
  13856.     p1 moveTo: 250 @ 210.
  13857.     p2 _ PlanetGlyph new initialize.
  13858.     p2 form2.
  13859.     p2 moveTo: 150 @ 210.
  13860.     p3 _ PlanetGlyph new initialize.
  13861.     p3 form3.
  13862.     p3 moveTo: 110 @ 210.
  13863.     self addGlyph: p1; addGlyph: p2; addGlyph: p3.
  13864.     Transcript cr; show: '..adding control sliders'.
  13865.     h1 _ (HSliderGlyph on: r1) minVal: 0.1; maxVal: 200.0; value: 100.0; moveTo: 150 @ 400.
  13866.     h2 _ (HSliderGlyph on: r2) minVal: 0.1; maxVal: 200.0; value: 40.0; moveTo: 360 @ 400.
  13867.     self addGlyph: h1; addGlyph: h2.
  13868.     Transcript cr; show: '..adding interface constraints'.
  13869.     StayConstraint var: p1 xVar strength: #default.
  13870.     StayConstraint var: p1 yVar strength: #default.
  13871.     c2 _ Constraint
  13872.             names: #(theta r xp xs )
  13873.             methods: #('xp _ xs + (r * theta cos)' 'xs _ xp - (r * theta cos)' ).
  13874.     c3 _ Constraint
  13875.             names: #(theta r yp ys )
  13876.             methods: #('yp _ ys + (r * theta sin)' 'ys _ yp - (r * theta sin)' ).
  13877.     (Constraint
  13878.             names: #(theta pretheta r )
  13879.             methods: #('theta _ pretheta + (5.0/r)' ))
  13880.         var: theta1 var: theta1 last var: r1 strength: #required.
  13881.     c2 copy var: theta1 var: r1 var: p1 xVar var: p2 xVar strength: #required.
  13882.     c3 copy var: theta1 var: r1 var: p1 yVar var: p2 yVar strength: #required.
  13883.     (Constraint
  13884.             names: #(theta pretheta r )
  13885.             methods: #('theta _ pretheta + (10.0/r)' ))
  13886.         var: theta2 var: theta2 last var: r2 strength: #required.
  13887.     c2 copy var: theta2 var: r2 var: p2 xVar var: p3 xVar strength: #required.
  13888.     c3 copy var: theta2 var: r2 var: p2 yVar var: p3 yVar strength: #required.
  13889.     Transcript cr; show: 'finished'!
  13890. initialize
  13891.     super initialize.
  13892.     self create! !
  13893.  
  13894. !ThreePlanetDemo methodsFor: 'public'!
  13895. open
  13896.     "ThreePlanetDemo new open"
  13897.  
  13898.     | topView |
  13899.     topView _ SpecialSystemView
  13900.                 model: nil
  13901.                 label: 'Planet Demo (Fake Gravity)'
  13902.                 minimumSize: 525 @ 425.
  13903.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  13904.     topView controller open! !
  13905.  
  13906. !ThreePlanetDemo methodsFor: 'testing'!
  13907. isAnimated
  13908.     ^true! !
  13909.  
  13910. !ThreePlanetDemo methodsFor: 'background processing'!
  13911. computeBackgroundPlan
  13912.     ^Planner extractPlanFromVariables: (Array with: theta1 with: theta2)! !
  13913.  
  13914. !StatsDemo methodsFor: 'initialize-release'!
  13915. initialize
  13916.     "Make a scene with points mapped to underlying points via scale constraints."
  13917.     "StatsDemo new initialize"
  13918.  
  13919.     | scaleC r p1 p2 textC fontC t |
  13920.     super initialize.
  13921.     scale _ FreeVariable value: 1.0.
  13922.     xOffset _ FreeVariable new.
  13923.     yOffset _ FreeVariable new.
  13924.     scaleC _ Constraint
  13925.         names: #(src dst scale offset)
  13926.         methods: #(
  13927.             'dst _ ((src * scale) / 100.0) rounded + offset'
  13928.             'src _ ((dst - offset) asFloat * 100.0) / scale').
  13929.     textC _ Constraint
  13930.         names: #(x y text)
  13931.         methods: #('text _ ''x: '', x printString, '' y: '', y printString').
  13932.     fontC _ Constraint
  13933.         names: #(painted font)
  13934.         methods: #(
  13935.             'font _ painted
  13936.                 ifTrue: [TextStyle default fontAt: 2]
  13937.                 ifFalse: [TextStyle default fontAt: 1]').
  13938.     r _ Random new.
  13939.     1 to: 20 do:
  13940.         [: i |
  13941.          p1 _ PointGlyph new moveTo: ((r next * 200.0) - 100.0)@((r next * 150.0) - 75.0).
  13942.          p1 xVar defaultStay.
  13943.          p1 yVar defaultStay.
  13944.          p2 _ PaintablePointGlyph new.
  13945.          (scaleC copy)
  13946.             var: p1 xVar var: p2 xVar
  13947.             var: scale var: xOffset strength: #required.
  13948.          (scaleC copy)
  13949.             var: p1 yVar var: p2 yVar
  13950.             var: scale var: yOffset strength: #required.
  13951.          self addGlyph: p2.
  13952.          t _ TextGlyph new.
  13953.          (textC copy) var: p1 xVar var: p1 yVar var: t textVar strength: #required.
  13954.          (fontC copy) var: p2 paintedVar var: t fontVar strength: #required.
  13955.          t box leftVar setValue: 15.
  13956.          t box topVar setValue: (45 + (14 * i)).
  13957.          self addGlyph: t].
  13958.  
  13959.     self addGlyph: ((HSliderGlyph on: xOffset)
  13960.         minVal: 0.0; maxVal: 400.0; value: 300;
  13961.         moveTo: 80@20).
  13962.     self addGlyph: ((HSliderGlyph on: yOffset)
  13963.         minVal: 0.0; maxVal: 400.0; value: 200;
  13964.         moveTo: 80@35).
  13965.     self addGlyph: ((HSliderGlyph on: scale)
  13966.         minVal: 1.0; maxVal: 350.0; value: 88.0;
  13967.         moveTo: 230@20).
  13968.     self addGlyph: ((TextButtonGlyph new)
  13969.         text: 'Paint'; script: 'model paintSelection';
  13970.         moveTo: 325@20).
  13971.     self addGlyph: ((TextButtonGlyph new)
  13972.         text: 'Unpaint'; script: 'model unpaintSelection';
  13973.         moveTo: 372@20).
  13974.     self addGlyph: ((TextButtonGlyph new)
  13975.         text: 'Brush'; script: 'model brushIn: view mode: #paint';
  13976.         moveTo: 420@20).
  13977.     SceneView openOn: self.! !
  13978.  
  13979. !StatsDemo methodsFor: 'painting'!
  13980. brushAt: aPoint mode: paintMode
  13981.     "Paint or unpaint the given data point, depending on which paint mode we are in (#paint or #unpaint)."
  13982.  
  13983.     | oldState change |
  13984.     change _ false.
  13985.     glyphs value do:
  13986.         [: g |
  13987.          ((g class == PaintablePointGlyph) and:
  13988.           [g boundingBox containsPoint: aPoint]) ifTrue:
  13989.             [oldState _ g painted.
  13990.              (paintMode == #paint)
  13991.                 ifTrue: [g painted: true]
  13992.                 ifFalse: [g painted: false].
  13993.              (g painted == oldState) ifFalse:
  13994.                 [change _ true]]].
  13995.     ^change!
  13996. brushIn: aView mode: paintMode
  13997.  
  13998.     | change |
  13999.     Cursor crossHair showWhile:
  14000.         [[Sensor anyButtonPressed] whileFalse.    "wait for a button"
  14001.          [Sensor anyButtonPressed] whileTrue:
  14002.             [change _
  14003.                 self brushAt: aView controller adjustedCursorPoint mode: paintMode.
  14004.              change ifTrue:
  14005.                 [aView displayScene]]].!
  14006. paintSelection
  14007.  
  14008.     selected do:
  14009.         [: g |
  14010.          (g class == PaintablePointGlyph) ifTrue:
  14011.             [g painted: true]].!
  14012. unpaintSelection
  14013.  
  14014.     selected do:
  14015.         [: g |
  14016.          (g class == PaintablePointGlyph) ifTrue:
  14017.             [g painted: false]].! !
  14018.  
  14019. !TwoPlanetDemo methodsFor: 'initialize-release'!
  14020. create
  14021.     | v1 h1 v2 v3 v4 c cx cy |
  14022.     Transcript cr; show: 'Building the ' , self class name , '..'.
  14023.     Transcript cr; show: '..adding planets'.
  14024.     gravity _ FreeVariable new.
  14025.     planet1 _ PlanetGlyph new initialize.
  14026.     planet1 form2.
  14027.     planet1 moveTo: 150 @ 200.
  14028.     planet2 _ PlanetGlyph new initialize.
  14029.     planet2 form2b.
  14030.     planet2 moveTo: 350 @ 250.
  14031.     self addGlyph: planet1; addGlyph: planet2.
  14032.     Transcript cr; show: '..adding control sliders'.
  14033.     v1 _ PlanetVectorGlyph new initialize.
  14034.     v1 moveTo: 50 @ 50.
  14035.     v2 _ PlanetVectorGlyph new initialize.
  14036.     v2 moveTo: 125 @ 50.
  14037.     v3 _ PlanetVectorGlyph new initialize.
  14038.     v3 moveTo: 375 @ 50.
  14039.     v4 _ PlanetVectorGlyph new initialize.
  14040.     v4 moveTo: 450 @ 50.
  14041.     self addGlyph: v1; addGlyph: v2; addGlyph: v3; addGlyph: v4.
  14042.     h1 _ (HSliderGlyph on: gravity) minVal: 0.0; maxVal: 1000000.0; value: 30.0; moveTo: 250 @ 50. 
  14043.     self addGlyph: h1.
  14044.     Transcript cr; show: '..adding stay constraints'.
  14045.     StayConstraint var: v1 p1 xVar strength: #default.
  14046.     StayConstraint var: v1 p1 yVar strength: #default.
  14047.     StayConstraint var: v2 p1 xVar strength: #default.
  14048.     StayConstraint var: v2 p1 yVar strength: #default.
  14049.     StayConstraint var: v3 p1 xVar strength: #default.
  14050.     StayConstraint var: v3 p1 yVar strength: #default.
  14051.     StayConstraint var: v4 p1 xVar strength: #default.
  14052.     StayConstraint var: v4 p1 yVar strength: #default.
  14053.     Transcript cr; show: '..adding interface constraints'.
  14054.     c _ Constraint names: #(v prev deltav ) methods: #('v _ prev + (deltav // 5)' 'deltav _ (v - prev) * 5' ).
  14055.     c copy
  14056.         var: v1 arrowHead vector xVar
  14057.         var: v1 arrowHead vector xVar last
  14058.         var: v2 arrowHead vector xVar
  14059.         strength: #required.
  14060.     c copy
  14061.         var: v1 arrowHead vector yVar
  14062.         var: v1 arrowHead vector yVar last
  14063.         var: v2 arrowHead vector yVar
  14064.         strength: #required.
  14065.     c copy
  14066.         var: v4 arrowHead vector xVar
  14067.         var: v4 arrowHead vector xVar last
  14068.         var: v3 arrowHead vector xVar
  14069.         strength: #required.
  14070.     c copy
  14071.         var: v4 arrowHead vector yVar
  14072.         var: v4 arrowHead vector yVar last
  14073.         var: v3 arrowHead vector yVar
  14074.         strength: #required.
  14075.     Transcript cr; show: '..adding behavior constraints'.
  14076.     c _ Constraint names: #(v prev deltav ) methods: #(
  14077.         'v _ ((prev + (deltav // 5)) < 0
  14078.             ifTrue: [0]
  14079.             ifFalse: [(prev + (deltav // 5)) > 500
  14080.                 ifTrue: [500]
  14081.                 ifFalse: [prev + (deltav // 5)]])' 'deltav _ (v - prev) * 5' ).
  14082.     c copy
  14083.         var: planet1 xVar
  14084.         var: planet1 xVar last
  14085.         var: v1 arrowHead vector xVar
  14086.         strength: #required.
  14087.     c copy
  14088.         var: planet1 yVar
  14089.         var: planet1 yVar last
  14090.         var: v1 arrowHead vector yVar
  14091.         strength: #required.
  14092.     c copy
  14093.         var: planet2 xVar
  14094.         var: planet2 xVar last
  14095.         var: v4 arrowHead vector xVar
  14096.         strength: #required.
  14097.     c copy
  14098.         var: planet2 yVar
  14099.         var: planet2 yVar last
  14100.         var: v4 arrowHead vector yVar
  14101.         strength: #required.
  14102.     cx _ Constraint names: #(p1x p1y p2x p2y ax g) methods: #(
  14103.         'ax _ (g * (
  14104.             (p2x - p1x) abs < 1
  14105.                 ifTrue: [0]
  14106.                 ifFalse: [((p2x - p1x) / ((p2x - p1x) squared + (p2y - p1y) squared) sqrt)
  14107.                         / ((p2x - p1x) squared + (p2y - p1y) squared)]))').
  14108.     cy _ Constraint names: #(p1x p1y p2x p2y ay g) methods: #(
  14109.         'ay _ (g * (
  14110.             (p2y - p1y) abs < 1
  14111.                 ifTrue: [0]
  14112.                 ifFalse: [((p2y - p1y) / ((p2x - p1x) squared + (p2y - p1y) squared) sqrt)
  14113.                         / ((p2x - p1x) squared + (p2y - p1y) squared)]))').
  14114.     cx copy
  14115.         var: planet1 xVar last
  14116.         var: planet1 yVar last
  14117.         var: planet2 xVar last
  14118.         var: planet2 yVar last
  14119.         var: v2 arrowHead vector xVar
  14120.         var: gravity
  14121.         strength: #strongDefault.
  14122.     cy copy
  14123.         var: planet1 xVar last
  14124.         var: planet1 yVar last
  14125.         var: planet2 xVar last
  14126.         var: planet2 yVar last
  14127.         var: v2 arrowHead vector yVar
  14128.         var: gravity
  14129.         strength: #strongDefault.
  14130.     cx copy
  14131.         var: planet2 xVar last
  14132.         var: planet2 yVar last
  14133.         var: planet1 xVar last
  14134.         var: planet1 yVar last
  14135.         var: v3 arrowHead vector xVar
  14136.         var: gravity
  14137.         strength: #strongDefault.
  14138.     cy copy
  14139.         var: planet2 xVar last
  14140.         var: planet2 yVar last
  14141.         var: planet1 xVar last
  14142.         var: planet1 yVar last
  14143.         var: v3 arrowHead vector yVar
  14144.         var: gravity
  14145.         strength: #strongDefault.
  14146.     Transcript cr; show: 'finished'!
  14147. initialize
  14148.     super initialize.
  14149.     self create! !
  14150.  
  14151. !TwoPlanetDemo methodsFor: 'public'!
  14152. open
  14153.     "TwoPlanetDemo new open"
  14154.  
  14155.     | topView |
  14156.     topView _ SpecialSystemView
  14157.                 model: nil
  14158.                 label: 'Planet Demo (Real Gravity)'
  14159.                 minimumSize: 525 @ 425.
  14160.     topView borderWidth: 1; addSubView: (SceneView new initialize model: self).
  14161.     topView controller open! !
  14162.  
  14163. !TwoPlanetDemo methodsFor: 'testing'!
  14164. isAnimated
  14165.     ^true! !
  14166.  
  14167. !TwoPlanetDemo methodsFor: 'background processing'!
  14168. computeBackgroundPlan
  14169.     ^Planner extractPlanFromVariables: (Array with: gravity)! !
  14170.  
  14171. !MarimbaPlayer methodsFor: 'public'!
  14172. open
  14173.     "Construct and open a user interface for myself."
  14174.     "MarimbaPlayer open"
  14175.  
  14176.     self addTitleAndButtons.
  14177.     self addSpeedAndMasterVolumeControls.
  14178.     self addMarimbaControls.
  14179.     SceneView openOn: self.! !
  14180.  
  14181. !MarimbaPlayer methodsFor: 'initialize-release'!
  14182. extractVariations: marimbaList from: aScore
  14183.     "Extract the variations for each marimba from the given score. marimbaList is a collection containing a variations list for each marimba used in the piece. A variations list is simply a list of Adagio voices of the given score corresponding to the variations (Adagio voice = one variation). The first part in the list is the 'basic' variation for that marimba. Voices are renumbered to correspond to marimbas.
  14184.  
  14185.     Example:
  14186.         self extractVariations: #((1 2 3) (4 2 5) (6) (7)) from: myScore"
  14187.  
  14188.     | parts |
  14189.     1 to: marimbaList size do:
  14190.         [: i |
  14191.          parts _ (marimbaList at: i) collect:
  14192.             [: v |
  14193.              aScore select: [: note | note voice == v]].
  14194.          parts do:
  14195.             [: part |
  14196.              part do: [: note | note voice: i]].
  14197.          scores at: i put: parts.
  14198.          (boxCounts at: i) setValue: (parts size + 1).
  14199.          (selectedVariations at: i) setValue:
  14200.             ((selectedVariations at: i) value min: (parts size + 1))].
  14201.  
  14202.     (marimbaList size + 1) to: boxCounts size do:
  14203.         [: i |
  14204.          (boxCounts at: i) setValue: 1.
  14205.          (selectedVariations at: i) setValue: 1 "off"].!
  14206. initialize
  14207.  
  14208.     super initialize.
  14209.     title _ FreeVariable value: 'Untitled'.
  14210.     masterVolume _ FreeVariable new.
  14211.     rate _ FreeVariable new.
  14212.     boxCounts _ (1 to: 8) collect: [: i | FreeVariable new].
  14213.     selectedVariations _ (1 to: 8) collect: [: i | FreeVariable new].
  14214.     volumes _ (1 to: 8) collect: [: i | FreeVariable new].
  14215.     scores _ (1 to: 8) collect: [: i | Array new].
  14216.     loopTime _ 10.
  14217.     stopFlag _ true.! !
  14218.  
  14219. !MarimbaPlayer methodsFor: 'songs'!
  14220. amaxoxo
  14221.  
  14222.     title setValue: 'Amaxoxo (The Frog Song)'.
  14223.     self
  14224.         extractVariations: #((1) (2 3 4) (5 6 7) (8 9 10))
  14225.         from: (Score fromFile: 'Amaxoxo.gio').!
  14226. hombi
  14227.  
  14228.     title setValue: 'Hombi'.
  14229.     self
  14230.         extractVariations: #((1) (2) (3) (4) (5 6) (7 8 9 10))
  14231.         from: (Score fromFile: 'Hombi.gio').!
  14232. longing
  14233.  
  14234.     title setValue: 'Longing'.
  14235.     self
  14236.         extractVariations: #((1 2) (3) (4) (5) (6) (7) (8))
  14237.         from: (Score fromFile: 'Magnum.gio').!
  14238. magnum
  14239.  
  14240.     title setValue: 'Longing'.
  14241.     self
  14242.         extractVariations: #((1 2) (3) (4) (5) (6) (7) (8))
  14243.         from: (Score fromFile: 'Magnum.gio').!
  14244. ndofo
  14245.  
  14246.     title setValue: 'Ndofonichibiawa II'.
  14247.     self
  14248.         extractVariations: #((1) (2) (3) (4) (5) (6))
  14249.         from: (Score fromFile: 'Ndofo2.gio').!
  14250. ritz
  14251.  
  14252.     title setValue: 'Puttin'' on the Ritz'.
  14253.     self
  14254.         extractVariations: #((1) (2) (3) (4) (5) (6) (7) (8))
  14255.         from: (Score fromFile: 'Ritz.gio').!
  14256. taesarewa
  14257.  
  14258.     title setValue: 'Taesarewa'.
  14259.     self
  14260.         extractVariations: #((1) (2) (3) (4) (5) (6) (7))
  14261.         from: (Score fromFile: 'Taesarewa.gio').! !
  14262.  
  14263. !MarimbaPlayer methodsFor: 'performing'!
  14264. collectAndResetActiveScores
  14265.     "Answer a collection of variations (Scores) to be played. If a given marimba is silent, then its score will be nil in the active scores list."
  14266.  
  14267.     | activeScores selectedVariation score |
  14268.     loopTime _ 10.    "one tenth second miniumum"
  14269.     activeScores _ OrderedCollection new: 16.
  14270.     1 to: scores size do:
  14271.         [: i |
  14272.          selectedVariation _ ((selectedVariations at: i) value) - 1.
  14273.          (selectedVariation > 0)
  14274.             ifTrue:
  14275.                 [score _ ((scores at: i) at: selectedVariation).
  14276.                  score prepareToPlay.
  14277.                  loopTime _ loopTime max: score scoreTime.
  14278.                  activeScores add: score]
  14279.             ifFalse:
  14280.                 [activeScores add: nil]].
  14281.     ^activeScores!
  14282. playLoop
  14283.     "Repeat the song endlessly according to the rate, scoreOn, and volume parameters."
  14284.  
  14285.     | activeScores |
  14286.     [stopFlag] whileFalse:
  14287.         [activeScores _ self collectAndResetActiveScores.
  14288.          self playOneCycle: activeScores].
  14289.  
  14290.     Midi allNotesOff.    "turn off all notes in case I was rudely interrupted."!
  14291. playOneCycle: activeScores
  14292.     "Play once through the given active scores, unless stopFlag becomes true first."
  14293.  
  14294.     | currentTick currentMSClock nextTick i score |
  14295.     currentTick _ 0.
  14296.     [stopFlag | (currentTick > loopTime)] whileFalse:
  14297.         [currentMSClock _ Time millisecondClockValue.
  14298.          nextTick _ currentTick + 50. "max delay: half second"
  14299.          i _ activeScores size.
  14300.          [i > 0] whileTrue:
  14301.             [score _ activeScores at: i.
  14302.              (score == nil) ifFalse:
  14303.                 [nextTick _ nextTick min:
  14304.                     (score
  14305.                         playThrough: currentTick
  14306.                         volume: (volumes at: i) value rounded)].
  14307.              i _ i - 1].
  14308.          self wait: (nextTick - currentTick) after: currentMSClock.
  14309.          currentTick _ nextTick].!
  14310. start
  14311.     "Fork a process to play the scores in the background."
  14312.  
  14313.     (stopFlag) ifTrue:
  14314.         [Midi openPort: 0.
  14315.          stopFlag _ false.
  14316.          ([self playLoop] newProcess)
  14317.             priority: (Processor timingPriority); resume].!
  14318. stop
  14319.     "Raise the stop flag to tell the background process to terminate."
  14320.  
  14321.     stopFlag _ true.!
  14322. wait: tickCount after: startMillisecond
  14323.     "Pause until the given number of virtual clock ticks have elapsed following the given millisecond clock value."
  14324.  
  14325.     | millisecondsSoFar millisecondsToWait sleepTime |
  14326.     (tickCount = 0) ifTrue: [self error: 'zero wait time!!'].
  14327.     millisecondsSoFar _ (Time millisecondClockValue - startMillisecond).
  14328.     [millisecondsToWait _ ((tickCount * 10) asFloat / rate value) rounded.
  14329.      ((millisecondsSoFar < millisecondsToWait) & stopFlag not)] whileTrue:
  14330.         [sleepTime _ (millisecondsToWait - millisecondsSoFar) min: 500.
  14331.          (Delay forMilliseconds: sleepTime) wait.
  14332.          millisecondsSoFar _ millisecondsSoFar + sleepTime].! !
  14333.  
  14334. !MarimbaPlayer methodsFor: 'interface'!
  14335. addMarimbaControls
  14336.     "Add the marimba controls."
  14337.  
  14338.     | where label buttons slider lastSlider |
  14339.     where _ 45@150.
  14340.  
  14341.     "headers"
  14342.     self addGlyph: (TextGlyph new
  14343.         text: 'Off'; moveTo: where + (49@-20)).
  14344.     self addGlyph: (TextGlyph new
  14345.         text: '1'; moveTo: where + (75@-20)).
  14346.     self addGlyph: (TextGlyph new
  14347.         text: '2'; moveTo: where + (101@-20)).
  14348.     self addGlyph: (TextGlyph new
  14349.         text: '3'; moveTo: where + (127@-20)).
  14350.     self addGlyph: (TextGlyph new
  14351.         text: '4'; moveTo: where + (153@-20)).
  14352.  
  14353.     "the marimba controls"
  14354.     1 to: 8 do:
  14355.         [: i |
  14356.          label _ (TextGlyph new) text: ' Marimba ', i printString, ':'.
  14357.          label box leftVar defaultStay.
  14358.          buttons _ RadioButtonsGlyph new.
  14359.          buttons countVar requireEquals: (boxCounts at: i).
  14360.          buttons valueVar requireEquals: (selectedVariations at: i).
  14361.          slider _ HSliderGlyph new.
  14362.          slider valueVar requireEquals: (volumes at: i).
  14363.          OffsetConstraint from: (label box topVar) to: (buttons box topVar) require: 0.
  14364.          OffsetConstraint from: (buttons box topVar) to: (slider box topVar) require: 0.
  14365.          OffsetConstraint from: (label box rightVar) to: (buttons box leftVar) require: 12.
  14366.          (lastSlider == nil) ifFalse:
  14367.             [OffsetConstraint from: (lastSlider box leftVar) to: (slider box leftVar) require: 0].
  14368.          label moveTo: where.
  14369.          slider box left: 240.
  14370.          self addGlyph: label; addGlyph: buttons; addGlyph: slider.
  14371.          lastSlider _ slider.
  14372.          where _ where + (0@25)].!
  14373. addSpeedAndMasterVolumeControls
  14374.  
  14375.     | volumeLabel speedLabel volumeSlider speedSlider | 
  14376.     volumeLabel _ (TextGlyph new) text: 'Master Volume:'.
  14377.     speedLabel _ (TextGlyph new) text: 'Speed:'.
  14378.     volumeSlider _ (HSliderGlyph on: masterVolume)
  14379.         minVal: 0.0; maxVal: 127.0; value: 127.0;
  14380.         script: 'Midi control: 7 value: val rounded chan: 1'.
  14381.     speedSlider _ (HSliderGlyph on: rate)
  14382.         minVal: 0.8; maxVal: 4.0; value: 1.0.
  14383.     OffsetConstraint from: (volumeLabel box topVar) to: (volumeSlider box topVar) require: 0.
  14384.     OffsetConstraint from: (speedLabel box topVar) to: (speedSlider box topVar) require: 0.
  14385.     OffsetConstraint from: (volumeLabel box leftVar) to: (speedLabel box leftVar) require: 0.
  14386.     OffsetConstraint from: (volumeSlider box leftVar) to: (speedSlider box leftVar) require: 0.
  14387.     OffsetConstraint from: (volumeLabel box rightVar) to: (volumeSlider box leftVar) require: 12.
  14388.     OffsetConstraint from: (volumeLabel box bottomVar) to: (speedLabel box topVar) require: 12.
  14389.     (volumeLabel box) left: 85; top: 64.
  14390.     self addGlyph: volumeLabel; addGlyph: speedLabel; addGlyph: volumeSlider; addGlyph: speedSlider.!
  14391. addTitleAndButtons
  14392.     "Add the title text and the start and stop buttons."
  14393.  
  14394.     | titleGlyph |
  14395.     titleGlyph _ TextGlyph new
  14396.         font: (TextStyle default fontAt: 5);
  14397.         moveTo: 195@30.
  14398.     titleGlyph textVar requireEquals: title.
  14399.     title setValue: 'Song Title'.
  14400.     self addGlyph: ((AttachableMenuGlyph forHost: titleGlyph)
  14401.         addMenuEntry: 'Amaxoxo (The Frog Song)' script: 'model amaxoxo';
  14402.         addMenuEntry: 'Hombi' script: 'model hombi';
  14403.         addMenuEntry: 'Ndofonichibiawa II' script: 'model ndofo';
  14404.         addMenuEntry: 'Ritz' script: 'model ritz';
  14405.         addMenuEntry: 'Longing For Summer' script: 'model longing';
  14406.         addMenuEntry: 'Taesarewa' script: 'model taesarewa').
  14407.     self addGlyph: titleGlyph.
  14408.  
  14409.     self addGlyph: (TextButtonGlyph new
  14410.         text: ' Start '; script: 'model start';
  14411.         moveTo: 40@70).
  14412.     self addGlyph: (TextButtonGlyph new
  14413.         text: ' Stop '; script: 'model stop';
  14414.         moveTo: 37@95).! !
  14415.  
  14416. MacDrawDemo comment:
  14417. '                            ***** Complex Graphical User Interfaces (MacDraw II) *****
  14418.  
  14419. This demo was taken from the MacDraw II Dashed Lines dialog box, a user interface widget for defining the number and length of the black and white dashes that, together, comprise a dashed line.  In the original MacDraw II, this dialog box was implemented completely in Pascal: the programmer designed the box, extracted the constraints, hand-solved them, coded them in Pascal, and debugged and debugged and debugged.  In this version, the behavior is almost completely defined by constraints.  Even the existence or non-existence of the dashes is defined by constraints.
  14420.  
  14421. This dialog box uses three basic types of constraints: data consistency constraints, graphical constraints, and behavioral constraints.  Data consistency constraints include: no dash shall be shorted than 5 pixels.  No dash shall be longer than 125 pixels.  There must be at least two dashes.  There can be no more than six dashes.  Etc.  Graphical constraints include keeping the "draggers" aligned with the right end of their respective dash expect for the last one which can be dragged to the far right edge to delete a dash.  Behavioral constraints are basically internal but include such things as the existence of dashes and draggers, and "snapping" action which occurs when the last dragger is released between the right end of its dash and the right edge of the box.
  14422.  
  14423. Interesting actions to try include: (1) trying to shrink a dash too far, (2) trying to grow a dash too large, (3) dragging the last dragger to the far right, (4) dragging the dragger on the far right (if there you left it there) off the far right "parking" place, (5) trying to compact a dash on the right by shoving it against the edge with a dash from the middle, and (6) releasing the last dragger half-way between the end of its dash and the right edge of the box.
  14424. '!
  14425.  
  14426. !MacDrawDemo methodsFor: 'initialize-release'!
  14427. create1
  14428.     | c d |
  14429.     Transcript cr; show: 'Building the ' , self class name , '..'.
  14430.     Transcript cr; show: '..adding the dashes'.
  14431.     dashes _ d _ Array new: 6.
  14432.     1 to: d size do: [:i | d at: i put: (MacDrawDashGlyph new initialize: i)].
  14433.     (d at: 1) left0 value: MacDrawDemo leftEdge.
  14434.     2 to: d size + 1 do: 
  14435.         [:i | 
  14436.         (d at: i - 1) right0 value: (d at: i - 1) left0 value + (d at: i - 1) length0 value.
  14437.         (d at: i - 1) right1 value: (d at: i - 1) left1 value + (d at: i - 1) length1 value.
  14438.         (d at: i - 1) right2 value: (d at: i - 1) left2 value + (d at: i - 1) length2 value.
  14439.         (d at: i - 1) right3 value: (d at: i - 1) left3 value + (d at: i - 1) length3 value.
  14440.         (d at: i - 1) color value: i even.
  14441.         i > d size
  14442.             ifFalse: 
  14443.                 [(d at: i) left0 value: (d at: i - 1) right0 value.
  14444.                 (d at: i) left1 value: (d at: i - 1) right1 value.
  14445.                 (d at: i) left2 value: (d at: i - 1) right2 value.
  14446.                 (d at: i) left3 value: (d at: i - 1) right3 value]].
  14447.     1 to: d size do: [:i | self addGlyph: (d at: i)].
  14448.     Transcript cr; show: '..adding the dash constraints'.
  14449.     (StayConstraint var: (d at: 1) left0 strength: #required) name: 'initial length0 stay'.
  14450.     (StayConstraint var: (d at: 1) left1 strength: #required) name: 'initial length1 stay'.
  14451.     (StayConstraint var: (d at: 1) left2 strength: #required) name: 'initial length2 stay'.
  14452.     (StayConstraint var: (d at: 1) left3 strength: #required) name: 'initial length3 stay'.
  14453.     2 to: d size do: 
  14454.         [:i | 
  14455.         (EqualityConstraint
  14456.             var: (d at: i - 1) right0
  14457.             var: (d at: i) left0
  14458.             strength: #required) name: ((i-1) printString), ':right0 = ', (i printString), ':left0'.
  14459.         (EqualityConstraint
  14460.             var: (d at: i - 1) right1
  14461.             var: (d at: i) left1
  14462.             strength: #required) name: ((i-1) printString), ':right1 = ', (i printString), ':left1'.
  14463.         (EqualityConstraint
  14464.             var: (d at: i - 1) right2
  14465.             var: (d at: i) left2
  14466.             strength: #required) name: ((i-1) printString), ':right2 = ', (i printString), ':left2'.
  14467.         (EqualityConstraint
  14468.             var: (d at: i - 1) right3
  14469.             var: (d at: i) left3
  14470.             strength: #required) name: ((i-1) printString), ':right3 = ', (i printString), ':left3'].
  14471.     (StayConstraint var: (d at: 1) color strength: #required) name: 'initial color stay'.
  14472.     c _ Constraint names: #(left right ) methods: #('left _ right not' 'right _ left not' ).
  14473.     2 to: d size do: [:i | (c copy
  14474.             var: (d at: i - 1) color
  14475.             var: (d at: i) color
  14476.             strength: #required) name: (i printString), ':color alternate'].
  14477.     self create2!
  14478. create2
  14479.     | d |
  14480.     Transcript cr; show: '..adding the draggers'.
  14481.     d _ draggers _ Array new: dashes size.
  14482.     1 to: d size do: [:i | d at: i put: (MacDrawDraggerGlyph new initialize: i)].
  14483.     d with: dashes do: [:drag :dash | drag dash: dash scene: self].
  14484.     d do: [:each | self addGlyph: each].
  14485.     (d at: 1) height value: 20 + MacDrawDemo dragTop.
  14486.     Transcript cr; show: '..adding the dragger constraints'.
  14487.     (StayConstraint var: (d at: 1) height strength: #required) name: 'initial height'.
  14488.     2 to: d size do: [:i | (OffsetConstraint
  14489.             from: (d at: i - 1) height
  14490.             to: (d at: i) height
  14491.             strength: #required
  14492.             offset: MacDrawDemo dragBox height) name: i printString, ':height descent'].
  14493.     1 to: d size do: [:i |
  14494.             drag _ d at: i.
  14495.             dash _ dashes at: i.
  14496.             self defaultFlexiForDash: dash andDragger: drag atIndex: i].
  14497.     self create3!
  14498. create3
  14499.     | c |
  14500.     Transcript cr; show: '..adding the ruler'.
  14501.     self addGlyph: MacDrawRulerGlyph new.
  14502.     sparedragger _ FreeVariable value: 0.
  14503.     selfvariable _ FreeVariable value: self.
  14504.     Transcript cr; show: '..adding the existence constraints'.
  14505.     c _ Constraint names: #(exists offset ) methods: #('exists _ (offset = MacDrawDemo rightEdge) not' ).
  14506.     1 to: dashes size do: [:i | (c copy
  14507.             var: (dashes at: i) exists
  14508.             var: (draggers at: i) offset
  14509.             strength: #required)
  14510.             name: i printString , ':dash exists _ dragger atRight'].
  14511.     3 to: dashes size do: [:i | ((Constraint names: #(exists dashexists spare ) methods: (Array with: 'exists _ dashexists | (spare = ', i printString, ')'))
  14512.             var: (draggers at: i) exists
  14513.             var: (dashes at: i) exists
  14514.             var: sparedragger
  14515.             strength: #required)
  14516.             name: i printString , ':dragger exists _ dash exists or spare=', i printString].
  14517.     Transcript cr; show: '..initializing'.
  14518.     self cleanUpFor: nil and: nil.
  14519.     Transcript cr; show: 'finished'!
  14520. defaultFlexiForDash: aDash andDragger: aDragger atIndex: i 
  14521.     aDragger doDashDraggerAlignDefault: i!
  14522. initialize
  14523.     super initialize.
  14524.     self create1! !
  14525.  
  14526. !MacDrawDemo methodsFor: 'public'!
  14527. open
  14528.     "MacDrawDemo new open"
  14529.  
  14530.     | topView |
  14531.     topView _ SpecialSystemView
  14532.                 model: nil
  14533.                 label: 'MacDraw II Dialog Box'
  14534.                 minimumSize: 600 @ 400.
  14535.     topView borderWidth: 1; addSubView: (MacDrawDemoView new initialize model: self).
  14536.     topView controller open! !
  14537.  
  14538. !MacDrawDemo methodsFor: 'access'!
  14539. lastdash
  14540.     | l |
  14541.     l _ dashes inject: nil into: [:last :dash | dash exists value
  14542.                     ifTrue: [dash]
  14543.                     ifFalse: [last]].
  14544.     "l == dashes last ifFalse: [Transcript cr; show: 'Notice: lastdash ~~ dashes last']."
  14545.     ^l!
  14546. seconddash
  14547.     ^dashes at: 2! !
  14548.  
  14549. !MacDrawDemo methodsFor: 'direct manipulation'!
  14550. cleanUpFor: aDragger and: aDash 
  14551.     | i |
  14552.     aDragger notNil
  14553.         ifTrue: 
  14554.             [i _ dashes indexOf: aDash.
  14555.             self defaultFlexiForDash: aDash andDragger: aDragger atIndex: i].
  14556.     dashes do: 
  14557.         [:each | 
  14558.         each right1 value: each right0 value.
  14559.         each right2 value: each right1 value.
  14560.         each right3 value: each right2 value.
  14561.         each length1 value: each length0 value.
  14562.         each length2 value: each length1 value.
  14563.         each length3 value: each length2 value.
  14564.         each left1 value: each left0 value.
  14565.         each left2 value: each left1 value.
  14566.         each left3 value: each left2 value]!
  14567. computeSpare: ignore
  14568.     | i |
  14569.     i _ dashes indexOf: self lastdash.
  14570.     ^i = dashes size
  14571.                 ifTrue: [0]
  14572.                 ifFalse: [i + 1]!
  14573. editConstraints1For: aDragger and: aDash at: idx into: cons
  14574.     "== == == == == == == == == == == == == == == == == == == == == == == == 
  14575.                             mouse
  14576.                                 |
  14577.                                 v
  14578.     dash3        dash3        dash3*        dash3        dash3"
  14579.     cons addFirst: ((XMouseConstraint
  14580.             var: aDash right3
  14581.             strength: #required
  14582.             offset: aDragger offset value - Sensor mousePoint x) name: 'on ', idx printString).!
  14583. editConstraints2For: aDragger and: aDash at: idx into: cons
  14584.     "== == == == == == == == == == == == == == == == == == == == == == == == 
  14585.                             dragger
  14586.                                 ^
  14587.                                 |
  14588.     dash1        dash1        dash1*        dash1        dash1"
  14589.     ((aDash == self lastdash | aDragger isSpare) and: [(aDash == self seconddash) not])
  14590.         ifTrue: [aDragger doDashDraggerAlignMovement: idx].!
  14591. editConstraints3For: aDragger and: aDash at: idx into: cons
  14592.     "== == == == == == == == == == == == == == == == == == == == == == == == 
  14593.                             spare
  14594.                                 ^
  14595.                                 |
  14596.     dash0        dash0        dash0*        dash0        dash0"
  14597.     CalculateSpareConstraint isNil ifTrue: [CalculateSpareConstraint _ (Constraint
  14598.         names: #(spare scene offset)
  14599.         methods: #('spare _ scene computeSpare: offset'))
  14600.         name: 'spare computation' ].
  14601.     cons add: (CalculateSpareConstraint copy
  14602.                 var: sparedragger
  14603.                 var: selfvariable
  14604.                 var: aDash exists
  14605.                 strength: #required).!
  14606. editConstraints4For: aDragger and: aDash at: idx into: cons
  14607.     | each |
  14608.     "== == == == == == == == == == == == == == == == == == == == == == == == 
  14609.     dash3        dash3        dash3*        dash3        dash3
  14610.     stay        stay                    stay        stay
  14611.  
  14612.     dash2        dash2        dash2*        dash2        dash2
  14613.     stay        stay                    stay        stay
  14614.  
  14615.     dash1        dash1        dash1*        dash1        dash1
  14616.     stay        stay                    stay        stay
  14617.  
  14618.     dash0        dash0        dash0*        dash0        dash0
  14619.     stay        stay                    stay        stay"
  14620.     1 to: dashes size do: [:i | each _ dashes at: i.
  14621.         each == aDash
  14622.             ifFalse: 
  14623.                 [cons add: ((StayConstraint var: each length3 strength: #required) name: i printString, ':length3 stay').
  14624.                 cons add: ((StayConstraint var: each length2 strength: #required) name: i printString, ':length2 stay').
  14625.                 cons add: ((StayConstraint var: each length1 strength: #required) name: i printString, ':length1 stay').
  14626.                 cons add: ((StayConstraint var: each length0 strength: #required) name: i printString, ':length0 stay').]].!
  14627. editConstraints5For: aDragger and: aDash at: idx into: cons
  14628.     "== == == == == == == == == == == == == == == == == == == == == == == == 
  14629.     dash3        dash3        dash3*        dash3        dash3
  14630.                                 | minimum length
  14631.                                 v
  14632.     dash2        dash2        dash2*        dash2        dash2"
  14633.     MinLengthConstraint isNil ifTrue: [MinLengthConstraint _ Constraint
  14634.         names: #(v pv )
  14635.         methods: #('v _ pv max: MacDrawDemo minDash' )].
  14636.     cons add: ((MinLengthConstraint copy
  14637.             var: aDash length2
  14638.             var: aDash length3
  14639.             strength: #required) name: idx printString, ': length2 = min length3').!
  14640. editConstraints6For: aDragger and: aDash at: idx into: cons
  14641.     "== == == == == == == == == == == == == == == == == == == == == == == == 
  14642.     dash1        dash1        dash1*        dash1        dash1
  14643.                                 | maximum length
  14644.                                 v
  14645.     dash0        dash0        dash0*        dash0        dash0"
  14646.     MaxLengthConstraint isNil ifTrue: [MaxLengthConstraint _ Constraint
  14647.         names: #(v pv )
  14648.         methods: #('v _ pv min: MacDrawDemo maxDash' )].
  14649.     cons add: ((MaxLengthConstraint copy
  14650.             var: aDash length0
  14651.             var: aDash length1
  14652.             strength: #required) name: idx printString, ': length0 = min max length1').!
  14653. editConstraints7For: aDragger and: aDash at: idx into: cons
  14654.     "== == == == == == == == == == == == == == == == == == == == == == == == 
  14655.     dash2        dash2        dash2*        dash2        dash2
  14656.                                                         | not beyond right edge
  14657.                                                         v
  14658.     dash1        dash1        dash1*        dash1        dash1"
  14659.     MinRightConstraint isNil ifTrue: [MinRightConstraint _ Constraint
  14660.         names: #(v pv )
  14661.         methods: #('v _ pv min: MacDrawDemo rightEdge' )].
  14662.     MinRight2Constraint isNil ifTrue: [MinRight2Constraint _ Constraint
  14663.         names: #(v pv )
  14664.         methods: #('v _ pv min: MacDrawDemo rightEdge - 1' )].
  14665.     aDragger isSpare
  14666.         ifTrue: [cons add: ((MinRightConstraint copy
  14667.                     var: aDragger dash right1
  14668.                     var: aDragger dash right2
  14669.                     strength: #required) name: idx printString, ': right1 = min right2')]
  14670.         ifFalse:[aDash == self lastdash
  14671.                     ifTrue: [cons add: ((MinRightConstraint copy
  14672.                             var: self lastdash right1
  14673.                             var: self lastdash right2
  14674.                             strength: #required)
  14675.                             name: idx printString, ': right1 = min right2')]
  14676.                     ifFalse: [cons add: ((MinRight2Constraint copy
  14677.                             var: self lastdash right1
  14678.                             var: self lastdash right2
  14679.                             strength: #required)
  14680.                             name: idx printString, ': right1 = min-1 right2')]].!
  14681. editConstraintsFor: aDragger and: aDash 
  14682.     | cons idx |
  14683.     cons _ OrderedCollection new.
  14684.     idx _ dashes indexOf: aDash.
  14685.     self editDebugFor: aDragger and: aDash mark: 0.
  14686.     self editConstraints1For: aDragger and: aDash at: idx into: cons.
  14687.     self editDebugFor: aDragger and: aDash mark: 1.
  14688.     self editConstraints2For: aDragger and: aDash at: idx into: cons.
  14689.     self editDebugFor: aDragger and: aDash mark: 2.
  14690.     self editConstraints3For: aDragger and: aDash at: idx into: cons.
  14691.     self editDebugFor: aDragger and: aDash mark: 3.
  14692.     self editConstraints4For: aDragger and: aDash at: idx into: cons.
  14693.     self editDebugFor: aDragger and: aDash mark: 4.
  14694.     self editConstraints5For: aDragger and: aDash at: idx into: cons.
  14695.     self editDebugFor: aDragger and: aDash mark: 5.
  14696.     self editConstraints6For: aDragger and: aDash at: idx into: cons.
  14697.     self editDebugFor: aDragger and: aDash mark: 6.
  14698.     self editConstraints7For: aDragger and: aDash at: idx into: cons.
  14699.     self editDebugFor: aDragger and: aDash mark: 7.
  14700.     ^cons!
  14701. editDebugFor: aDragger and: aDash mark: aMark
  14702.     | collec st s0 s1 s2 s3 d | 
  14703. true ifTrue: [^self].
  14704. collec _ Array
  14705.     with: (Array with: 5 with: (dashes at: 5))
  14706.     with: (Array with: 6 with: (dashes at: 6)).
  14707. st _ String new writeStream. st nextPut: $[. aMark printOn: st. st nextPut: $].
  14708. s0 _ String new writeStream. s0 nextPutAll: '0:'.
  14709. s1 _ String new writeStream. s1 nextPutAll: '1:'.
  14710. s2 _ String new writeStream. s2 nextPutAll: '2:'.
  14711. s3 _ String new writeStream. s3 nextPutAll: '3:'.
  14712. collec do: [:each |
  14713. d _ (each at: 2).
  14714. st tab; tab. (each at: 1) printOn: st. st tab; tab.
  14715. s3 tab. d left3 value printOn: s3. s3 tab.
  14716. d length3 value printOn: s3. s3 tab.
  14717. d right3 value printOn: s3. s3 tab.
  14718. s2 tab. d left2 value printOn: s2. s2 tab.
  14719. d length2 value printOn: s2. s2 tab.
  14720. d right2 value printOn: s2. s2 tab.
  14721. s1 tab. d left1 value printOn: s1. s1 tab.
  14722. d length1 value printOn: s1. s1 tab.
  14723. d right1 value printOn: s1. s1 tab.
  14724. s0 tab. d left0 value printOn: s0. s0 tab.
  14725. d length0 value printOn: s0. s0 tab.
  14726. d right0 value printOn: s0. s0 tab].
  14727. aMark = 0 ifTrue: [Transcript nextPutAll: '--------------------------'; cr].
  14728. Transcript nextPutAll: st contents; cr.
  14729. Transcript nextPutAll: s3 contents; cr; nextPutAll: s2 contents; cr.
  14730. Transcript nextPutAll: s1 contents; cr; nextPutAll: s0 contents; cr.
  14731. Transcript show: ''! !
  14732.  
  14733. !Inspector methodsFor: 'text'!
  14734. textMenu
  14735.     "Inspector flushMenus"
  14736.     TextMenu == nil ifTrue:
  14737.         [TextMenu _ ActionMenu
  14738.             labelList: #((again undo) (copy cut paste) ('do it' 'print it' inspect) (accept cancel) ('edit form'))
  14739.             selectors: #(again undo copySelection cut paste doIt printIt inspectIt accept cancel formEdit)].
  14740.     ^ TextMenu! !
  14741.  
  14742. Midi comment:
  14743. 'See my class comment.'!
  14744.  
  14745. !ParseNode methodsFor: 'DeltaBlue'!
  14746. allVariables
  14747.     "Answer a set containing all variables used in this parse tree."
  14748.  
  14749.     | vars |
  14750.     vars _ IdentitySet new.
  14751.     self apply:
  14752.         [: node |
  14753.          (node isMemberOf: VariableNode)
  14754.             ifTrue: [vars add: node name asSymbol].
  14755.          true].
  14756.  
  14757.     self removePredefinedVarsFrom: vars.
  14758.     ^vars!
  14759. assignedTo
  14760.     "Answer a collection of the variables assigned to in this parse tree."
  14761.  
  14762.     | vars |
  14763.     vars _ IdentitySet new.
  14764.     self apply:
  14765.         [: node |
  14766.          (node isMemberOf: AssignmentNode)
  14767.             ifTrue: [vars add: node variable name asSymbol].
  14768.          true].
  14769.  
  14770.     self removePredefinedVarsFrom: vars.
  14771.     ^vars!
  14772. referenced
  14773.     "Answer a collection of the variables that are referenced but not assigned to in this parse tree."
  14774.  
  14775.     | vars |
  14776.     vars _ IdentitySet new.
  14777.     self apply:
  14778.         [: node |
  14779.          (node isMemberOf: VariableNode)
  14780.             ifTrue: [vars add: node name asSymbol. true]
  14781.             ifFalse:
  14782.                 [(node isMemberOf: AssignmentNode)
  14783.                     ifTrue: [vars addAll: node value referenced. false]
  14784.                     ifFalse: [true]]].
  14785.  
  14786.     self removePredefinedVarsFrom: vars.
  14787.     ^vars!
  14788. removePredefinedVarsFrom: varList
  14789.     "Remove the pre-defined variable names from the given collection."
  14790.  
  14791.     #(self super true false nil thisContext) do:
  14792.         [: predefinedVar |
  14793.             varList remove: predefinedVar ifAbsent: []].! !
  14794.  
  14795. !ReturnNode methodsFor: 'DeltaBlue'!
  14796. apply: aBlock
  14797.  
  14798.     (aBlock value: self) ifTrue:
  14799.         [expr apply: aBlock].! !
  14800.  
  14801. !CascadeNode methodsFor: 'DeltaBlue'!
  14802. apply: aBlock
  14803.  
  14804.     (aBlock value: self) ifTrue:
  14805.         [receiver apply: aBlock.
  14806.          messages do: [: m | m apply: aBlock]].! !
  14807.  
  14808. !BlockNode methodsFor: 'DeltaBlue'!
  14809. apply: aBlock
  14810.  
  14811.     (aBlock value: self) ifTrue:
  14812.         [statements do: [: s | s apply: aBlock]].! !
  14813.  
  14814. !AssignmentNode methodsFor: 'DeltaBlue'!
  14815. apply: aBlock
  14816.  
  14817.     (aBlock value: self) ifTrue:
  14818.         [variable apply: aBlock.
  14819.          value apply: aBlock].!
  14820. value
  14821.  
  14822.     ^value!
  14823. variable
  14824.  
  14825.     ^variable! !
  14826.  
  14827. !MethodNode methodsFor: 'DeltaBlue'!
  14828. apply: aBlock
  14829.  
  14830.     (aBlock value: self) ifTrue:
  14831.         [block apply: aBlock].! !
  14832.  
  14833. !MessageNode methodsFor: 'DeltaBlue'!
  14834. apply: aBlock
  14835.  
  14836.     (aBlock value: self) ifTrue:
  14837.         [(receiver notNil)
  14838.             ifTrue: [receiver apply: aBlock].
  14839.          arguments do: [: a | a apply: aBlock]].! !
  14840.  
  14841. !LeafNode methodsFor: 'DeltaBlue'!
  14842. apply: aBlock
  14843.  
  14844.     aBlock value: self.! !
  14845.  
  14846. !VariableNode methodsFor: 'DeltaBlue'!
  14847. name
  14848.  
  14849.     ^name! !
  14850.  
  14851. FreeVariable comment:
  14852. 'I represent an unconstraint variable. I turn into a ConstrainedVariable when a constraint is added to me.
  14853.  
  14854. Instance variables:
  14855.     value        my value; changed by constraints, read by client <Object>
  14856. '!
  14857.  
  14858. !FreeVariable methodsFor: 'initialize-release'!
  14859. initialize
  14860.  
  14861.     value _ 0.! !
  14862.  
  14863. !FreeVariable methodsFor: 'access'!
  14864. addConstraint: aConstraint
  14865.     "Turn myself into a constrained variable and then add the constraint."
  14866.  
  14867.     | newSelf |
  14868.     newSelf _ ConstrainedVariable value: value.
  14869.     newSelf addConstraint: aConstraint.
  14870.     self become: newSelf.!
  14871. constraints
  14872.  
  14873.     ^#()!
  14874. last
  14875.     "Turn myself into a HistoryVariable and then return my previous state variable."
  14876.  
  14877.     | newSelf newLast |
  14878.     newSelf _ HistoryVariable value: value.
  14879.     newLast _ newSelf last.
  14880.     self become: newSelf.
  14881.     ^newLast!
  14882. mark
  14883.     "I'm never marked."
  14884.  
  14885.     ^0!
  14886. mark: ignore
  14887.     "I don't have any constraints, so ignore this message."!
  14888. removeConstraint: ignore
  14889.     "I don't have any constraints, so ignore this message."!
  14890. speciallast
  14891.     "Turn myself into a HistoryVariable and then return my previous state variable."
  14892.  
  14893.     | newSelf newLast |
  14894.     newSelf _ HistoryVariable value: value.
  14895.     newLast _ newSelf speciallast.
  14896.     self become: newSelf.
  14897.     ^newLast!
  14898. stay
  14899.     "Answer true since I am unconstrained."
  14900.  
  14901.     ^true!
  14902. usedBy
  14903.  
  14904.     ^#()!
  14905. value
  14906.     "Answer my value."
  14907.  
  14908.     ^value!
  14909. value: anObject
  14910.     "Set my value."
  14911.  
  14912.     value _ anObject.! !
  14913.  
  14914. !FreeVariable methodsFor: 'changes'!
  14915. changeIn: aBlock
  14916.     "Allow the given block to change my value."
  14917.  
  14918.     aBlock value.!
  14919. changeIn: aBlock strength: strengthSymbol
  14920.     "Allow the given block to change my value."
  14921.  
  14922.     aBlock value.!
  14923. setAll: variables to: values
  14924.     "Attempt to assign the given values to the given variables using a strength of #preferred. This is an all-or-nothing operation; if any variable cannot be changed due to a stronger constraint then no variable is changed."
  14925.  
  14926.     (ConstrainedVariable new) setAll: variables to: values strength: #preferred.!
  14927. setAll: variables to: values strength: strengthSymbol
  14928.     "Attempt to assign the given values to the given variables using the given strength. This is an all-or-nothing operation; if any variable cannot be changed due to a stronger constraint then no variable is changed."
  14929.  
  14930.     (ConstrainedVariable new) setAll: variables to: values strength: strengthSymbol.!
  14931. setValue: aValue
  14932.     "Change my value."
  14933.  
  14934.     value _ aValue.!
  14935. setValue: aValue strength: strengthSymbol
  14936.     "Change my value."
  14937.  
  14938.     value _ aValue.! !
  14939.  
  14940. !FreeVariable methodsFor: 'history'!
  14941. advanceHistory
  14942.     "I have no history, so this is a noop."!
  14943. advanceHistory: newValue
  14944.     "I am the end of a history chain, so update my state and return."
  14945.  
  14946.     value _ newValue.! !
  14947.  
  14948. !FreeVariable methodsFor: 'stay constraints'!
  14949. defaultStay
  14950.  
  14951.     ^StayConstraint var: self strength: #default!
  14952. preferredStay
  14953.  
  14954.     ^StayConstraint var: self strength: #preferred!
  14955. requiredStay
  14956.  
  14957.     ^StayConstraint var: self strength: #required!
  14958. strongDefaultStay
  14959.  
  14960.     ^StayConstraint var: self strength: #strongDefault!
  14961. strongPreferredStay
  14962.  
  14963.     ^StayConstraint var: self strength: #strongPreferred!
  14964. weakDefaultStay
  14965.  
  14966.     ^StayConstraint var: self strength: #weakDefault! !
  14967.  
  14968. !FreeVariable methodsFor: 'equality constraints'!
  14969. requireEquals: aVariable
  14970.     "Insall a required equality constraint between me and the given variable."
  14971.  
  14972.     ^EqualityConstraint var: self var: aVariable strength: #required! !
  14973.  
  14974. !FreeVariable methodsFor: 'conversions'!
  14975. @ aVariable
  14976.  
  14977.     ^(PointGlyph new) setX: self setY: aVariable! !
  14978.  
  14979. !FreeVariable methodsFor: 'printing'!
  14980. printOn: aStream
  14981.  
  14982.     aStream nextPutAll: 'FreeVar(', self asOop printString, ', ', value printString, ')'.! !
  14983.  
  14984. ConstrainedVariable comment:
  14985. 'I represent a constrained variable. In addition to my value, I maintain the structure of the constraint graph, the current dataflow graph, and various parameters of interest to the DeltaBlue incremental constraint solver.
  14986.  
  14987. Instance variables:
  14988.     value            my value; changed by constraints, read by client <Object>
  14989.     constraints        normal constraints that reference me <Array of Constraint>
  14990.     determinedBy    the constraint that currently determines
  14991.                     my value (or nil if there isn''t one) <Constraint>
  14992.     walkStrength        my walkabout strength <Strength>
  14993.     stay            true if I am a planning-time constant <Boolean>
  14994.     mark            used by the planner to mark constraints <Number>'!
  14995.  
  14996. !ConstrainedVariable methodsFor: 'initialize-release'!
  14997. initialize
  14998.  
  14999.     value _ 0.
  15000.     constraints _ OrderedCollection new: 2.
  15001.     determinedBy _ nil.
  15002.     walkStrength _ Strength absoluteWeakest.
  15003.     stay _ true.
  15004.     mark _ 0.!
  15005. release
  15006.     "Break cycles (but leave me printable)."
  15007.  
  15008.     self initialize.! !
  15009.  
  15010. !ConstrainedVariable methodsFor: 'access'!
  15011. addConstraint: aConstraint
  15012.     "Add the given constraint to the set of all constraints that refer to me."
  15013.  
  15014.     constraints add: aConstraint.!
  15015. constraints
  15016.     "Answer the set of constraints that refer to me."
  15017.  
  15018.     ^constraints!
  15019. constraints: collectionOfConstraints
  15020.     "Set the the set of constraints that refer to me. Most clients should used addConstraints: and removeConstraints:."
  15021.  
  15022.     constraints _ collectionOfConstraints.!
  15023. determinedBy
  15024.     "Answer the constraint that determines my value in the current dataflow."
  15025.  
  15026.     ^determinedBy!
  15027. determinedBy: aConstraint
  15028.     "Set the given constraint to be the one that determines my value in the current data flow."
  15029.  
  15030.     determinedBy _ aConstraint.!
  15031. last
  15032.     "Turn myself into a HistoryVariable and then return the variable for my previous state."
  15033.  
  15034.     | newSelf newLast |
  15035.     newSelf _ (HistoryVariable new)
  15036.         value: value;
  15037.         constraints: constraints;
  15038.         determinedBy: determinedBy;
  15039.         walkStrength: walkStrength;
  15040.         stay: stay;
  15041.         mark: mark.
  15042.     newLast _ newSelf last.
  15043.     self become: newSelf.
  15044.     ^newLast!
  15045. mark
  15046.     "Answer my mark value."
  15047.  
  15048.     ^mark!
  15049. mark: markValue
  15050.     "Set my mark value."
  15051.  
  15052.     mark _ markValue.!
  15053. removeConstraint: c
  15054.     "Remove all traces of c from this variable."
  15055.  
  15056.     constraints remove: c ifAbsent: [].
  15057.     (determinedBy == c) ifTrue: [determinedBy _ nil].!
  15058. stay
  15059.     "Answer my stay flag."
  15060.  
  15061.     ^stay!
  15062. stay: aBoolean
  15063.     "Set my stay flag."
  15064.  
  15065.     stay _ aBoolean!
  15066. unsatisfiedConstraintsInto: aCollection
  15067.     "Add to the given collection all unsatisfied constraints that refer to me."
  15068.  
  15069.     | i c |
  15070.      i _ constraints size.
  15071.      [i > 0] whileTrue:
  15072.         [c _ constraints at: i.
  15073.          (c isSatisfied) ifFalse: [aCollection add: c].
  15074.          i _ i - 1].!
  15075. value
  15076.     "Answer my value."
  15077.  
  15078.     ^value!
  15079. value: anObject
  15080.     "Set my value."
  15081.  
  15082.     value _ anObject.!
  15083. walkStrength
  15084.     "Answer my walkabout strength in the current dataflow."
  15085.  
  15086.     ^walkStrength!
  15087. walkStrength: aStrength
  15088.     "Set my walkabout strength in the current dataflow."
  15089.  
  15090.     walkStrength _ aStrength.! !
  15091.  
  15092. !ConstrainedVariable methodsFor: 'changes'!
  15093. changeIn: aBlock
  15094.     "Attempt to add a prefered edit constraint to myself and execute the given block only if this constraint can be satisfied (i.e. no stronger constraint prevents me from changing)."
  15095.  
  15096.     self changeIn: aBlock strength: #preferred.!
  15097. changeIn: aBlock strength: strengthSymbol
  15098.     "Attempt to add an edit constraint of the given strength to myself and execute the given block only if this constraint can be satisfied (i.e. no stronger constraint prevents me from changing)."
  15099.  
  15100.     | editConstraint |
  15101.     editConstraint _ EditConstraint var: self strength: strengthSymbol.
  15102.     (editConstraint isSatisfied) ifTrue:
  15103.         [aBlock value.
  15104.          Planner propagateFrom: self].
  15105.     editConstraint destroyConstraint.!
  15106. setAll: variables to: values
  15107.     "Attempt to assign the given values to the given variables using a strength of #preferred. This is an all-or-nothing operation; if any variable cannot be changed due to a stronger constraint then no variable is changed."
  15108.  
  15109.     self setAll: variables to: values strength: #preferred.!
  15110. setAll: variables to: values strength: strengthSymbol
  15111.     "Attempt to assign the given values to the given variables using the given strength. This is an all-or-nothing operation; if any variable cannot be changed due to a stronger constraint then no variable is changed."
  15112.  
  15113.     | allSatisfied editConstraints editConstraint |
  15114.     (variables size = values size) ifFalse:
  15115.         [^self error: 'variable and value lists must be same size'].
  15116.  
  15117.     "add edit constraints"
  15118.     allSatisfied _ true.        "true iff all edit constraints are satisfied"
  15119.     editConstraints _ variables collect:
  15120.         [: v |
  15121.          editConstraint _ EditConstraint var: v strength: strengthSymbol.
  15122.          (editConstraint isSatisfied) ifFalse: [allSatisfied _ false].
  15123.          editConstraint].
  15124.  
  15125.     (allSatisfied) ifTrue:
  15126.         ["do the assignments only if all edit constraints are satisfied"
  15127.          variables with: values do:
  15128.             [: thisVar : thisValue |
  15129.              thisVar value: thisValue.
  15130.              Planner propagateFrom: thisVar]].
  15131.  
  15132.     "remove edit constraints"
  15133.     editConstraints do: [: c | c destroyConstraint].!
  15134. setValue: aValue
  15135.     "Attempt to assign the given value to me using a strength of #preferred."
  15136.  
  15137.     self setValue: aValue strength: #preferred.!
  15138. setValue: aValue strength: strengthSymbol
  15139.     "Attempt to assign the given value to me using the given strength."
  15140.     "Details: Allow stay propagation to propagate the new value as a side effect of adding a Stay constraint. We know the stay constraint can be added if it is stronger than my walkabout strength."
  15141.  
  15142.     | stayConstraint |
  15143.     ((Strength of: strengthSymbol) stronger: walkStrength) ifTrue:
  15144.         [value _ aValue.
  15145.          stayConstraint _ StayConstraint var: self strength: strengthSymbol.    "propogates new value"
  15146.          stayConstraint destroyConstraint].! !
  15147.  
  15148. !ConstrainedVariable methodsFor: 'printing'!
  15149. longPrintOn: aStream
  15150.  
  15151.     self shortPrintOn: aStream.
  15152.     aStream nextPutAll: '   Constraints: '.
  15153.     (constraints isEmpty)
  15154.         ifTrue: [aStream cr; tab; nextPutAll: 'none']
  15155.         ifFalse:
  15156.             [constraints do:
  15157.                 [: c | aStream cr; tab. c shortPrintOn: aStream]].
  15158.     (determinedBy isNil) ifFalse:
  15159.         [aStream cr; nextPutAll: '   Determined by: '.
  15160.          aStream cr; tab. determinedBy shortPrintOn: aStream].
  15161.     aStream cr.!
  15162. printOn: aStream
  15163.  
  15164.     (Sensor leftShiftDown)
  15165.         ifTrue: [self longPrintOn: aStream]
  15166.         ifFalse: [self shortPrintOn: aStream].!
  15167. shortPrintOn: aStream
  15168.  
  15169.     aStream nextPutAll: 'V(', self asOop printString, ', '.
  15170.     aStream nextPutAll: walkStrength printString, ', '.
  15171.     (stay isNil) ifFalse:
  15172.         [aStream nextPutAll: (stay ifTrue: ['stay, '] ifFalse: ['changing, '])].
  15173.     aStream nextPutAll: value printString.
  15174.     aStream nextPutAll: ')'.
  15175.     aStream cr.! !
  15176.  
  15177. HistoryVariable comment:
  15178. 'I represent a constrained variable with a past.
  15179.  
  15180. Instance variables:
  15181.     last        pointer to the variable representing my previous value <some kind of FreeVariable or nil>
  15182. '!
  15183.  
  15184. !HistoryVariable methodsFor: 'history'!
  15185. advanceHistory
  15186.     "Advance my history by sending my value to the next variable in the history chain, if there is one."
  15187.  
  15188.     (last == nil) ifFalse:
  15189.         [last advanceHistory: value].!
  15190. advanceHistory: newValue
  15191.     "This message is sent to each past state of a variable's history. The given value is used as the new value for this stage in the history chain. The previous value of this stage is passed to the next older stage via a recursive call to advanceHistory:. The recursion terminates when it reaches a stage with no previous state (i.e. last = nil)."
  15192.  
  15193.     | myOldValue |
  15194.     (last == nil)
  15195.         ifTrue: [value _ newValue]
  15196.          ifFalse:
  15197.             [myOldValue _ value.
  15198.              value _ newValue.
  15199.              last advanceHistory: myOldValue].!
  15200. last
  15201.     "Answer the DBVariable for my previous state. If there isn't one yet, create one and remember it."
  15202.  
  15203.     (last == nil) ifTrue:
  15204.         [last _ HistoryVariable value: value.
  15205.          last walkStrength: Strength required.
  15206.          last stay: false].
  15207.     ^last!
  15208. speciallast
  15209.     "Answer the DBVariable for my previous state. If there isn't one yet, create one and remember it."
  15210.  
  15211.     (last == nil) ifTrue:
  15212.         [last _ HistoryVariable value: value.
  15213.          last walkStrength: Strength absoluteWeakest.
  15214.          last stay: false].
  15215.     ^last! !
  15216.  
  15217. PianoRollView comment:
  15218. 'I represent a view of a PianoRoll.'!
  15219.  
  15220. !PianoRollView methodsFor: 'initialize-release'!
  15221. initialize
  15222.     "Initialize my instance variables."
  15223.  
  15224.     super initialize.
  15225.     timeOffset _ 0.
  15226.     timeScale _ 1.
  15227.     visibleNotes _ OrderedCollection new.
  15228.     rate _ 100.0.
  15229.     selected _ IdentitySet new.
  15230.     leftSelTime _ 0.
  15231.     rightSelTime _ 0.
  15232.     voiceActive _ Array new: 32 withAll: true.!
  15233. openOn: aScore
  15234.     "Open a new view of myself on the given score."
  15235.  
  15236.     | paletteView topView |
  15237.     paletteView _ PaletteView new.
  15238.     self model: aScore.
  15239.     self borderWidth: 1.
  15240.     self borderColor: Form black.
  15241.     self initializePalette:  paletteView.
  15242.     topView _ StandardSystemView new
  15243.         borderWidth: 1;
  15244.         borderColor: Form black;
  15245.         label: 'Piano Roll Editor';
  15246.         addSubView: paletteView
  15247.              in: (0@0 corner: 1@0.2) borderWidth: 1;
  15248.         addSubView: self
  15249.              in: (0@0.2 corner: 1@1) borderWidth: 1;
  15250.         minimumSize: 320@220.
  15251.     topView controller open.! !
  15252.  
  15253. !PianoRollView methodsFor: 'accessing'!
  15254. cacheUpdate
  15255.  
  15256.     | endTime startIndex endIndex note |
  15257.     endTime _ self endVisibleSpan.
  15258.     startIndex _ model indexBefore: (self startVisibleSpan - model maxDur).
  15259.     endIndex _ (model indexAfter: endTime).
  15260.     visibleNotes _ visibleNotes species new: (visibleNotes size).
  15261.     (startIndex = 0) ifTrue: [^self].
  15262.     startIndex to: endIndex do:
  15263.         [: index |
  15264.          note _ model at: index.
  15265.          "if the note overlaps the visible timespan, record it in visibleNotes"
  15266.          (((self visible: note time) or: [self visible: note offTime]) and:
  15267.           [voiceActive at: note voice])
  15268.             ifTrue:
  15269.                 [visibleNotes add:
  15270.                     (Association key: note value: (self noteBox: note))].
  15271.         (note time >= endTime) ifTrue: [^self]].!
  15272. rate
  15273.  
  15274.     ^rate!
  15275. rate: newRate
  15276.  
  15277.     rate _ newRate.!
  15278. timeOffset
  15279.  
  15280.     ^timeOffset!
  15281. timeOffset: aNumber
  15282.  
  15283.     timeOffset _ aNumber.
  15284.     self cacheUpdate.!
  15285. voiceMap
  15286.  
  15287.     ^voiceActive! !
  15288.  
  15289. !PianoRollView methodsFor: 'selections'!
  15290. addToSelection: aNote
  15291.  
  15292.     (selected includes: aNote) ifTrue: [^self].
  15293.     selected add: aNote.
  15294.     self displayNoteBoxOnDisplay: (self noteBox: aNote) selected: true.!
  15295. clearSelection
  15296.  
  15297.     selected _ selected species new.
  15298.     self displayView.!
  15299. nearestNote: aPoint
  15300.  
  15301.     visibleNotes do:
  15302.         [: noteAssociation |
  15303.          ((noteAssociation value) containsPoint: aPoint)
  15304.             ifTrue: [^noteAssociation key]].
  15305.     ^nil!
  15306. noteIsSelected: aNote
  15307.     "Answer true iff the given note is in the selection."
  15308.  
  15309.     ^selected includes: aNote!
  15310. removeFromSelection: aNote
  15311.  
  15312.     selected remove: aNote ifAbsent: [^self].
  15313.     self displayNoteBoxOnDisplay: (self noteBox: aNote) selected: false.!
  15314. selected
  15315.  
  15316.     ^selected!
  15317. timeRangeEnd
  15318.  
  15319.     ^rightSelTime!
  15320. timeRangeStart
  15321.  
  15322.     ^leftSelTime! !
  15323.  
  15324. !PianoRollView methodsFor: 'displaying'!
  15325. displayNoteBoxOnDisplay: noteBox selected: noteSelected
  15326.     "Display a note box directly on the display. Used for quick feedback."
  15327.  
  15328.     | box |
  15329.     box _ self insetDisplayBox.
  15330.     self
  15331.         on: Display at: box origin clip: box
  15332.         displayNoteBox: noteBox selected: noteSelected.!
  15333. displayStavesOn: aForm at: offset clip: clipBox
  15334.     "Display the pitch lines for a piano roll on the given form. A horizontal gray line is drawn for each black key of the piano. A darker line marks middle C."
  15335.  
  15336.     BlackKeyPitches do:
  15337.         [: pitch |
  15338.          self
  15339.             on: aForm
  15340.             at: offset
  15341.             clip: clipBox
  15342.             lineAt: (self pitchToY: pitch)
  15343.             rule: Form over
  15344.             mask: Form lightGray].
  15345.  
  15346.     self
  15347.         on: aForm
  15348.         at: offset
  15349.         clip: clipBox
  15350.         lineAt: (self pitchToY: 60)
  15351.         rule: Form over
  15352.         mask: Form gray.!
  15353. displayView
  15354.     "Externally visible method to display a score in piano-roll notation. Update visible note cache first."
  15355.  
  15356.     self cacheUpdate.
  15357.     self quickDisplayView.!
  15358. on: aForm at: offset clip: clipBox displayNoteBox: noteBox selected: noteSelected
  15359.     "Display a note box with the given shade of gray."
  15360.  
  15361.     self
  15362.         on: aForm
  15363.         at: offset
  15364.         clip: clipBox
  15365.         fill: noteBox
  15366.         rule: Form over
  15367.         mask: Form black.
  15368.     noteSelected ifTrue:
  15369.         [self
  15370.             on: aForm
  15371.             at: offset
  15372.             clip: clipBox
  15373.             fill: (noteBox expandBy: -1@-1)
  15374.             rule: Form erase
  15375.             mask: Form black].!
  15376. on: aForm at: offset clip: clipBox fill: rect rule: rule mask: mask
  15377.     "Fill a rectangle on the given form with the given shade of gray using the given rule."
  15378.  
  15379.     (BitBlt
  15380.         destForm: aForm
  15381.         sourceForm: nil
  15382.         halftoneForm: mask
  15383.         combinationRule: rule
  15384.         destOrigin: rect origin + offset
  15385.         sourceOrigin: 0@0
  15386.         extent: rect extent
  15387.         clipRect: clipBox)
  15388.             copyBits!
  15389. on: aForm at: offset clip: clipBox lineAt: y rule: rule mask: mask
  15390.     "Draw a horizontal line of the given shade of gray across the given form using the given rule."
  15391.  
  15392.     (BitBlt 
  15393.         destForm: aForm
  15394.         sourceForm: nil
  15395.         halftoneForm: mask
  15396.         combinationRule: rule
  15397.         destOrigin: (clipBox left@(y + offset y))
  15398.         sourceOrigin: 0@0
  15399.         extent: (clipBox width@1)
  15400.         clipRect: clipBox)
  15401.             copyBits!
  15402. quickDisplayView
  15403.     "Display a score in piano-roll notation."
  15404.  
  15405.     | box temp tempBox |
  15406.     box _ self insetDisplayBox.
  15407.     temp _ Form extent: box extent.
  15408.     tempBox _ temp computeBoundingBox.
  15409.     self
  15410.         displayStavesOn: temp
  15411.         at:  0@0 clip: tempBox.
  15412.     visibleNotes do:
  15413.         [: noteAssociation |
  15414.          self
  15415.             on: temp
  15416.             at:  0@0 clip: tempBox
  15417.             displayNoteBox: (noteAssociation value)
  15418.             selected: (self noteIsSelected: noteAssociation key)].
  15419.     self displaySelectionBarOn: temp at: 0@0 clip: tempBox.
  15420.     temp displayOn: Display at: box origin.! !
  15421.  
  15422. !PianoRollView methodsFor: 'time selection bar'!
  15423. displaySelBarInsides: selBar on: aForm at: offset clip: clipBox
  15424.     "Displays the selected time range in the selection bar along the bottom of the piano roll."
  15425.  
  15426.     | left right |
  15427.     "be sure that leftSelTime <= rightSelTime"
  15428.     (leftSelTime > rightSelTime) ifTrue: [rightSelTime _ leftSelTime].
  15429.  
  15430.     ((leftSelTime > self endVisibleSpan) or:
  15431.      [rightSelTime < self startVisibleSpan])
  15432.         ifTrue: [^self].    "no part of time selection is visible"
  15433.  
  15434.     (self visible: leftSelTime)
  15435.         ifTrue:
  15436.             ["draw left side of time selection bar"
  15437.              left _ self timeToX: leftSelTime.
  15438.              self
  15439.                 on: aForm at: offset clip: clipBox
  15440.                 fill: ((selBar topLeft + 1) corner: ((left@selBar bottom) - (0@1)))
  15441.                 rule: Form erase mask: Form black.
  15442.              self
  15443.                 on: aForm at: offset clip: clipBox
  15444.                 fill: ((left@selBar top) extent: (1@selBar height))
  15445.                 rule: Form over mask: Form black]
  15446.         ifFalse: [left _ selBar left].
  15447.  
  15448.     (self visible: rightSelTime)
  15449.         ifTrue:
  15450.             ["draw right side of time selection bar"
  15451.              right _ self timeToX: rightSelTime.
  15452.              self
  15453.                 on: aForm at: offset clip: clipBox
  15454.                 fill: (((right@selBar top) + 1) corner: (selBar bottomRight - 1))
  15455.                 rule: Form erase mask: Form black.
  15456.              self
  15457.                 on: aForm at: offset clip: clipBox
  15458.                 fill: ((right@selBar top) extent: (1@selBar height))
  15459.                 rule: Form over mask: Form black]
  15460.         ifFalse: [right _ selBar right - 1].
  15461.  
  15462.  
  15463.     "draw the center of the time selection bar"
  15464.     self
  15465.         on: aForm at: offset clip: clipBox
  15466.         fill: (((left@selBar top) + 1) corner: ((right@selBar bottom) - (0@1)))
  15467.         rule: Form over mask: Form gray.!
  15468. displaySelectionBarOn: aForm at: offset clip: clipBox
  15469.     "Displays the selection bar along the bottom of a piano roll."
  15470.  
  15471.     | selBar |
  15472.     selBar _ self selectionBar.
  15473.     aForm border: (selBar translateBy: offset) width: 1.
  15474.     self displaySelBarInsides: selBar on: aForm at: offset clip: clipBox.!
  15475. dragTimeMarker
  15476.     "Pick the time marker to move and drag it."
  15477.  
  15478.     | cursorTime |
  15479.     cursorTime _ self xToTime: controller viewCursorPoint x.
  15480.     ((cursorTime >= rightSelTime) or: [Sensor leftShiftDown])
  15481.         ifTrue: [self dragTimeMarker: #right]
  15482.         ifFalse: [self dragTimeMarker: #left].!
  15483. dragTimeMarker: which
  15484.     "Drag the specified time marker. The argument which is one of #left or #right."
  15485.  
  15486.     | viewBox cursorTime lastCursorTime lineX |
  15487.     viewBox _ self insetDisplayBox.
  15488.     [Sensor redButtonPressed]
  15489.         whileTrue:
  15490.             [cursorTime _ self xToTime: ((controller viewCursorPoint x) min: viewBox width - 1).
  15491.              cursorTime _
  15492.                 (cursorTime min: self endVisibleSpan)
  15493.                     max: self startVisibleSpan.
  15494.              (cursorTime ~= lastCursorTime)
  15495.                 ifTrue:
  15496.                     [lastCursorTime _ cursorTime.
  15497.                      "erase previously shown vertical bar, if any"
  15498.                      (lineX notNil) ifTrue:
  15499.                         [self reverseLine: lineX].
  15500.                      "reverse a vertical bar at the cursor time"
  15501.                     lineX _ self timeToX: cursorTime.
  15502.                     self reverseLine: lineX.
  15503.  
  15504.                      (which == #left) ifTrue:
  15505.                          [leftSelTime _ cursorTime.
  15506.                          rightSelTime _ leftSelTime max: rightSelTime].
  15507.                      (which == #right) ifTrue:
  15508.                          [rightSelTime _ cursorTime.
  15509.                          leftSelTime _ rightSelTime min: leftSelTime].
  15510.                      self
  15511.                         displaySelectionBarOn: Display
  15512.                         at: viewBox origin
  15513.                         clip: viewBox]].
  15514.  
  15515.     "erase previously shown vertical bar"
  15516.     self reverseLine: lineX.!
  15517. reverseLine: XPosition
  15518.     "Show a vertical line over the current time selection."
  15519.  
  15520.     | box x rect |
  15521.     box _ self insetDisplayBox.
  15522.     x _ (XPosition min: box width - 1) max: 0.
  15523.     rect _ x@15 extent: 1@(box height - 20).
  15524.     Display reverse: (rect translateBy: box origin)!
  15525. selectionBar
  15526.     "Answers the selection bar rectangle in view coordinates."
  15527.  
  15528.     | box |
  15529.     box _ self insetDisplayBox.
  15530.     ^(0@5) extent: (box width@6)! !
  15531.  
  15532. !PianoRollView methodsFor: 'scrolling'!
  15533. scrollTo: time
  15534.  
  15535.     self timeOffset: ((time min: model scoreTime) max: 0).
  15536.     self quickDisplayView.! !
  15537.  
  15538. !PianoRollView methodsFor: 'controller access'!
  15539. defaultControllerClass
  15540.     "Answer the class of my default controller."
  15541.  
  15542.     ^PianoRollController! !
  15543.  
  15544. !PianoRollView methodsFor: 'palette'!
  15545. addScaleButtons: aPaletteView
  15546.  
  15547.     | y |
  15548.     y _ 5.
  15549.     aPaletteView addButton: ((PaletteButton
  15550.         form: (' >< ') asParagraph asForm
  15551.         position: 10@y)
  15552.             downAction:
  15553.                 [timeScale _ (timeScale / 2) max: 0.25.
  15554.                  self displayView]).
  15555.     aPaletteView addButton: ((PaletteButton
  15556.         form: (' <-> ') asParagraph asForm
  15557.         position: 30@y)
  15558.             downAction:
  15559.                 [timeScale _ (timeScale * 2) min: 8.
  15560.                  self displayView]).!
  15561. addScrollButtons: aPaletteView
  15562.  
  15563.     | y bigIncrement smallIncrement |
  15564.     y _ 20.
  15565.     bigIncrement _ 100 * timeScale.
  15566.     smallIncrement _ 10 * timeScale.
  15567.     aPaletteView addButton: ((PaletteButton
  15568.         form: (' << ') asParagraph asForm
  15569.         position: 10@y)
  15570.             downAction: [self scrollTo: timeOffset - bigIncrement];
  15571.             whileDownAction: [self scrollTo: timeOffset - bigIncrement]).
  15572.     aPaletteView addButton: ((PaletteButton
  15573.         form: (' < ') asParagraph asForm
  15574.         position: 30@y)
  15575.             downAction: [self scrollTo: timeOffset - smallIncrement];
  15576.             whileDownAction: [self scrollTo: timeOffset - smallIncrement]).
  15577.     aPaletteView addButton: ((PaletteButton
  15578.         form: (' > ') asParagraph asForm
  15579.         position: 50@y)
  15580.             downAction: [self scrollTo: timeOffset + smallIncrement];
  15581.             whileDownAction: [self scrollTo: timeOffset + smallIncrement]).
  15582.     aPaletteView addButton: ((PaletteButton
  15583.         form: (' >> ') asParagraph asForm
  15584.         position: 70@y)
  15585.             downAction: [self scrollTo: timeOffset + bigIncrement];
  15586.             whileDownAction: [self scrollTo: timeOffset + bigIncrement]).!
  15587. addVoiceButtons: aPaletteView
  15588.  
  15589.     | x y |
  15590.     x _ 100.
  15591.     y _ 5.
  15592.     1 to: 10 do:
  15593.         [: voice |
  15594.          aPaletteView addButton: ((PaletteButton
  15595.             form: (' ', voice printString, ' ') asParagraph asForm
  15596.             position: x@y)
  15597.                 onTest: [voiceActive at: voice] fixTemps;
  15598.                 commitAction:
  15599.                     [voiceActive
  15600.                         at: voice
  15601.                         put: (voiceActive at: voice) not.
  15602.                      self displayView] fixTemps).
  15603.          x _ x + 20].
  15604.     x _ 100.
  15605.     y _ 20.
  15606.     11 to: 20 do:
  15607.         [: voice |
  15608.          aPaletteView addButton: ((PaletteButton
  15609.             form: (' ', voice printString, ' ') asParagraph asForm
  15610.             position: x@y)
  15611.                 onTest: [voiceActive at: voice] fixTemps;
  15612.                 commitAction:
  15613.                     [voiceActive
  15614.                         at: voice
  15615.                         put: (voiceActive at: voice) not.
  15616.                      self displayView] fixTemps).
  15617.          x _ x + 20].!
  15618. initializePalette: aPaletteView
  15619.  
  15620.     self addVoiceButtons: aPaletteView.
  15621.     self addScaleButtons: aPaletteView.
  15622.     self addScrollButtons: aPaletteView.! !
  15623.  
  15624. !PianoRollView methodsFor: 'mapping'!
  15625. noteBox: aNote
  15626.     "Answer a rectangle that is the given note's display box."
  15627.  
  15628.     | startX endX y |
  15629.     startX _ self timeToX: aNote time.
  15630.     endX _ self timeToX: aNote offTime.
  15631.     y _ (self pitchToY: aNote pitch) - 1.
  15632.     ^startX@y corner: endX@(y + BarHeight)!
  15633. pitchToY: pitch
  15634.     "Convert a pitch between 0 and 127 to a y offset."
  15635.  
  15636.     ^VOffset - (BarHeight * pitch)!
  15637. timeToX: time
  15638.     "Convert a score time to an x offset."
  15639.  
  15640.     ^(time - timeOffset) * timeScale!
  15641. xToTime: x
  15642.     "Convert an x offset to a score time."
  15643.  
  15644.     ^(x // timeScale) + timeOffset!
  15645. yToPitch: y
  15646.     "Convert a y offset to a pitch between 0 and 127."
  15647.  
  15648.     | pitch |
  15649.     pitch _ (y - VOffset) // BarHeight.
  15650.     ^((pitch max: 0) min: 127)! !
  15651.  
  15652. !PianoRollView methodsFor: 'visible time span'!
  15653. endVisibleSpan
  15654.  
  15655.     ^timeOffset + self visibleSpan!
  15656. startVisibleSpan
  15657.  
  15658.     ^timeOffset!
  15659. visible: aTime
  15660.  
  15661.     ^(aTime >= self startVisibleSpan) and: [aTime <= self endVisibleSpan]!
  15662. visibleSpan
  15663.  
  15664.     ^self insetDisplayBox width // timeScale! !
  15665.  
  15666. PaletteView comment:
  15667. 'I support a view containing a set of PaletteButtons. This is useful for building user interfaces such as the piano roll editor.'!
  15668.  
  15669. !PaletteView methodsFor: 'initialize-release'!
  15670. initialize
  15671.  
  15672.     super initialize.
  15673.     self
  15674.         model: nil;
  15675.         borderWidth: 1;
  15676.         insideColor: Form white.
  15677.     buttons _ OrderedCollection new.!
  15678. release
  15679.  
  15680.     buttons do: [: b | b release].
  15681.     buttons _ nil.! !
  15682.  
  15683. !PaletteView methodsFor: 'access'!
  15684. addButton: aButton
  15685.     "Add the given button to my button list."
  15686.  
  15687.     aButton view: self.
  15688.     buttons add: aButton.!
  15689. buttons
  15690.  
  15691.     ^buttons!
  15692. removeButton: aButton
  15693.     "Remove the given button from my button list."
  15694.  
  15695.     buttons remove: aButton ifAbsent: [].! !
  15696.  
  15697. !PaletteView methodsFor: 'display'!
  15698. displayView
  15699.     "Display all my buttons."
  15700.  
  15701.     buttons do: [: b | b display].! !
  15702.  
  15703. !PaletteView methodsFor: 'controller access'!
  15704. defaultControllerClass
  15705.     "Answer the class of my default controller."
  15706.  
  15707.     ^PaletteController! !
  15708.  
  15709. SpecialSystemView comment:
  15710. 'I provide a different window from for my contents. The title of the window is centered and the title bar extends the entire width of the window. Large or small title text is supported.'!
  15711.  
  15712. !SpecialSystemView methodsFor: 'controller access'!
  15713. defaultControllerClass
  15714.  
  15715.     ^SpecialSystemController! !
  15716.  
  15717. !SpecialSystemView methodsFor: 'custom labels'!
  15718. displayLabel
  15719.     "Customized label display for that special look-n-feel."
  15720.  
  15721.     self isCollapsed ifTrue: [^self].
  15722.     isLabelComplemented _ false.
  15723.     "draw my label"
  15724.     (self labelForm)
  15725.         displayOn: Display
  15726.         at: self labelDisplayBox topLeft
  15727.         clippingBox: self labelDisplayBox.!
  15728. displayView
  15729.     "Display my label."
  15730.  
  15731.     self displayLabel!
  15732. expandLabelFrame
  15733.     "Make my label frame fill the entire width of my display box. Assume that labelFrame topLeft has already been computed."
  15734.  
  15735.     labelFrame
  15736.         right: self displayBox width;
  15737.         bottom:
  15738.             ((labelText notNil)
  15739.                 ifTrue: [labelText boundingBox height]
  15740.                 ifFalse: [TextStyle default lineGrid]).!
  15741. label: aString 
  15742.     "Set aString to be my label. There are two label sizes: one for real computers and the other for small Macintoshes (toy computers)."
  15743.  
  15744.     self label: aString big: true.
  15745.     self expandLabelFrame.!
  15746. label: aString big: bigFlag
  15747.     "Set aString to be my label. Use big text if bigFlag is true, otherwise use small text."
  15748.  
  15749.     | style |
  15750.     (aString == nil)
  15751.         ifTrue: 
  15752.             [labelText _ nil.
  15753.              labelFrame region: (0@0 extent: 0@0)]
  15754.         ifFalse:
  15755.             [bigFlag
  15756.                 ifTrue:
  15757.                     [style _ TextStyle fontArray: (Array with:
  15758.                         ((TextStyle styleNamed: #default) fontAt: 1)).
  15759.                      style baseline: 11; lineGrid: 17]
  15760.                 ifFalse:
  15761.                     [style _ TextStyle fontArray: (Array with:
  15762.                         ((TextStyle styleNamed: #small) fontAt: 1)).
  15763.                       style baseline: 9; lineGrid: 13].
  15764.              labelText _ Paragraph withText: aString asText style: style.
  15765.              labelFrame region:
  15766.                 (0@0 extent: labelText boundingBox extent)].
  15767.  
  15768.     (iconView notNil & iconText isNil)
  15769.         ifTrue: [iconView text: self label asText].!
  15770. labelForm
  15771.     "A customized label display for that special look-n-feel."
  15772.  
  15773.     | form textBox textPlace leftEdge rightEdge |
  15774.     form _ Form extent: labelFrame extent.
  15775.  
  15776.     "draw the label text"
  15777.     textBox _ self labelTextBox.
  15778.     textPlace _ form boundingBox center -
  15779.                 (textBox center - textBox topLeft).
  15780.     (labelText notNil) ifTrue:
  15781.         [labelText
  15782.             displayOn: form
  15783.             at: textPlace + (4@1)
  15784.             clippingBox: textBox].
  15785.  
  15786.     "draw decorative fringes"
  15787.     leftEdge _ textPlace x - 12.
  15788.     rightEdge _ textPlace x + textBox width.
  15789.  
  15790.     "left side fringe"
  15791.     form fill: (0@0 corner: leftEdge@form height) mask: Form lightGray.
  15792.     form fill: ((leftEdge@0) extent: 12@form height) mask: Form white.
  15793.     form fill: ((leftEdge@0) extent: 4@form height) mask: Form black.
  15794.     form fill: ((leftEdge + 6@0) extent: 2@form height) mask: Form black.
  15795.     form fill: ((leftEdge + 11@0) extent: 1@form height) mask: Form black.
  15796.  
  15797.     "right side fringe"
  15798.     form fill: (rightEdge@0 corner: form extent) mask: Form lightGray.
  15799.     form fill: ((rightEdge@0) extent: 12@form height) mask: Form white.
  15800.     form fill: ((rightEdge@0) extent: 1@form height) mask: Form black.
  15801.     form fill: ((rightEdge + 4@0) extent: 2@form height) mask: Form black.
  15802.     form fill: ((rightEdge + 8@0) extent: 4@form height) mask: Form black.
  15803.  
  15804.     "draw the border over everything else"
  15805.     form
  15806.         border: form boundingBox
  15807.         widthRectangle: ((1@1) corner: (1@0)) mask: (Form black).
  15808.     ^form!
  15809. labelTextBox
  15810.     "Answer the rectangle containing just the text part of my label. This rectangle is in the coordinate system whose origin is the top-left corner of my label."
  15811.  
  15812.     | textWidth |
  15813.     (labelText isNil)
  15814.         ifTrue: [textWidth _ 8]
  15815.         ifFalse: [textWidth _ labelText boundingBox width + 8].
  15816.     ^(0@1 corner: labelFrame extent) insetBy:
  15817.         ((1 max: ((labelFrame width - textWidth) // 2)) @ 0)!
  15818. labelTextDisplayBox
  15819.     "Answer the rectangle containing just the text part of my label in the Display coordinate system."
  15820.  
  15821.     ^self labelTextBox translateBy: self labelDisplayBox origin!
  15822. reverseLabel
  15823.     "Reverse my label."
  15824.  
  15825.     Display reverse: (self labelTextDisplayBox).!
  15826. window: newWind viewport: newViewport
  15827.     "Intercept this message to allow me to re-compute my label frame when the view is re-sized."
  15828.  
  15829.     super window: newWind viewport: newViewport.
  15830.     self expandLabelFrame.! !
  15831.  
  15832. SceneView comment:
  15833. 'I am a view used to display a Scene. I may be scrolled by adjusting my offset. My default controller is SceneController.
  15834.  
  15835. SceneViews encapsulate the notion of a changing foreground and a fixed background during interactive updates. During an interaction (such as dragging), some of the glyphs will not change location or appearance. These are part of the "background". All glyphs that may change (the "foreground" glyphs) are painted against this unchanging backdrop during the interaction.
  15836.  
  15837. Instance Variables:
  15838.     offset                the current offset of this view (used for scrolling)
  15839.     enclosingRect         a rectangle large enough to contain all the objects in the scene, plus a small border (this is a cache that must be recomputed when glyphs are moved, added, or removed from the scene)
  15840.     backgroundForm        a <Form> containing the fixed background
  15841.     visibleForeground        the glyphs that are changing but not selected during an interaction
  15842.     selectedForeground    the selected glyphs that are changing during an interaction'!
  15843.  
  15844. !SceneView methodsFor: 'initialize-release'!
  15845. initialize
  15846.  
  15847.     super initialize.
  15848.     scrollOffset _ 0@0.
  15849.     enclosingRect _ 0@0 corner: 0@0.!
  15850. model: aScene
  15851.  
  15852.     super model: aScene.
  15853.     self computeBackground.! !
  15854.  
  15855. !SceneView methodsFor: 'label access'!
  15856. newLabel: aString
  15857.     "Change my label to be the given string."
  15858.  
  15859.     self topView deEmphasize.
  15860.     self topView newLabel: aString.
  15861.     self topView emphasize.! !
  15862.  
  15863. !SceneView methodsFor: 'scrolling'!
  15864. scrollOffset
  15865.     "Answer my scrolling offset."
  15866.  
  15867.     ^scrollOffset!
  15868. scrollOffset: aPoint
  15869.     "Set my scroll offset after first limiting it to lie within the envelope of permissible values."
  15870.  
  15871.     | limits |
  15872.     limits _ self scrollOffsetEnvelope.
  15873.     scrollOffset _
  15874.         ((aPoint max: limits origin) min: limits corner) rounded.!
  15875. scrollOffsetEnvelope
  15876.     "Answer the envelope of possible offset values (a possibly empty rectangle in the upper-left quadrant of the Cartesian plane)."
  15877.  
  15878.     | extent |
  15879.     extent _ (enclosingRect extent - self insetDisplayBox extent) max: 0@0.
  15880.     ^(0@0 - extent) corner: 0@0! !
  15881.  
  15882. !SceneView methodsFor: 'displaying'!
  15883. computeBackground
  15884.     "Compute the backgroundForm and the two lists, visibleForeground and selectedForeground. These are used by the 'displayFeedback' and 'displayFeedbackWithBox:width:' operations. Put glyphs that depend on a point being changed by a constraint into the foreground."
  15885.  
  15886.     | viewExtent viewOrigin clipBox |
  15887.     viewExtent _ (enclosingRect extent
  15888.         max: self insetDisplayBox extent)
  15889.         min: 1000@1000.
  15890.     backgroundForm _ Form extent: viewExtent.
  15891.     viewOrigin _ self viewOrigin.
  15892.     clipBox _ backgroundForm computeBoundingBox.
  15893.     self displayBorderOn: backgroundForm at: viewOrigin clip: clipBox.
  15894.  
  15895.     (model glyphsVar stay) ifTrue:
  15896.         [visibleForeground _ OrderedCollection new: 100.
  15897.          model visibleGlyphsDo:
  15898.             [: g |
  15899.              (g changing)
  15900.                 ifTrue: [visibleForeground add: g]
  15901.                 ifFalse: [g displayOn: backgroundForm at: viewOrigin clip: clipBox]].
  15902.  
  15903.          selectedForeground _ OrderedCollection new: 100.
  15904.          model selected do:
  15905.             [: g |
  15906.              (g changing)
  15907.                 ifTrue: [selectedForeground add: g]
  15908.                 ifFalse: [g highlightOn: backgroundForm at: viewOrigin clip: clipBox]]].!
  15909. displayBorderOn: aDisplayMedium at: aPoint clip: clipBox
  15910.     "Draw a boundary line that encloses all glyphs in the scene."
  15911.  
  15912.     | borderBox |
  15913.     borderBox _ (aPoint + enclosingRect origin) extent:
  15914.                     (enclosingRect extent max: clipBox extent).
  15915.     borderBox _ borderBox insetOriginBy: 4@4 cornerBy: 4@4.
  15916.     aDisplayMedium
  15917.         border: borderBox
  15918.         widthRectangle: (1@1 corner: 1@1)
  15919.         mask: (Form gray)
  15920.         clippingBox: clipBox.
  15921.  
  15922.     "display cross hairs at origin"
  15923.     aDisplayMedium black: (aPoint + (2@4) extent: 5@1).
  15924.     aDisplayMedium black: (aPoint + (4@2) extent: 1@5).!
  15925. displayFeedback
  15926.     "Update my display during a user interaction. The client must have called 'computeBackgroundWhileChanging:' to prepare for this operation."
  15927.  
  15928.     self displayFeedbackWithBox: nil width: nil.!
  15929. displayFeedbackWithBox: aRectangle width: w
  15930.     "Update my display during a user interaction. The client must have called 'computeBackground' to prepare for this operation. If it is not nil, the given rectangle is drawn with the given border width as additional feedback."
  15931.  
  15932.     | tempForm viewOrigin clipBox |
  15933.     tempForm _ backgroundForm deepCopy.
  15934.     viewOrigin _ self viewOrigin.
  15935.     clipBox _ tempForm computeBoundingBox.
  15936.     (model glyphsVar stay)
  15937.         ifTrue:
  15938.             [visibleForeground do:
  15939.                 [: g | g displayOn: tempForm at: viewOrigin clip: clipBox].
  15940.              selectedForeground do:
  15941.                 [: g | g highlightOn: tempForm at: viewOrigin clip: clipBox]]
  15942.         ifFalse:
  15943.             [model visibleGlyphsDo:
  15944.                 [: g | g displayOn: tempForm at: viewOrigin clip: clipBox].
  15945.              model selected do:
  15946.                 [: g | g highlightOn: tempForm at: viewOrigin clip: clipBox]].
  15947.     (aRectangle notNil) ifTrue:
  15948.         [tempForm
  15949.             border: (aRectangle translateBy: viewOrigin)
  15950.             widthRectangle: (w@w corner: w@w)
  15951.             mask: (Form black)
  15952.             clippingBox: clipBox].
  15953.     tempForm
  15954.         displayOn: Display
  15955.         at: self insetDisplayBox origin + scrollOffset
  15956.         clippingBox: self insetDisplayBox.!
  15957. displayScene
  15958.     "Display the scene."
  15959.  
  15960.     | viewExtent tempForm viewOrigin clipBox |
  15961.     viewExtent _ (enclosingRect extent
  15962.         max: self insetDisplayBox extent)
  15963.         min: 1000@1000.
  15964.     tempForm _ Form extent: viewExtent.
  15965.     viewOrigin _ self viewOrigin.
  15966.     clipBox _ tempForm computeBoundingBox.
  15967.     self displayBorderOn: tempForm at: viewOrigin clip: clipBox.
  15968.     model visibleGlyphsDo:
  15969.         [: g | g displayOn: tempForm at: viewOrigin clip: clipBox].
  15970.     model selected do:
  15971.         [: g | g highlightOn: tempForm at: viewOrigin clip: clipBox].
  15972.     tempForm
  15973.         displayOn: Display
  15974.         at: self insetDisplayBox origin + scrollOffset
  15975.         clippingBox: self insetDisplayBox.!
  15976. displayView
  15977.     "This method is called by the system when the top view is framed or moved."
  15978.  
  15979.     | myExtent |
  15980.     myExtent _ self insetDisplayBox extent.
  15981.     model viewWidthVar setValue: (myExtent x) strength: #required.
  15982.     model viewHeightVar setValue: (myExtent y) strength: #required.
  15983.     self computeEnclosingRectangle.
  15984.     self displayScene.!
  15985. isAlive
  15986.  
  15987.     ^model notNil! !
  15988.  
  15989. !SceneView methodsFor: 'controller access'!
  15990. defaultControllerClass
  15991.  
  15992.     ^SceneController! !
  15993.  
  15994. !SceneView methodsFor: 'coordinates'!
  15995. computeEnclosingRectangle
  15996.     "Compute a rectangle capable of enclosing all visible glyphs in this view. The rectangle's corners are computed and then expanded to allow room for a border. This method should be called any time glyphs are added, removed or moved."
  15997.  
  15998.     | min max g b |
  15999.     min _ 6@6.
  16000.     max _ 6@6.
  16001.     model visibleGlyphsDo:
  16002.         [: g |
  16003.          b _ g boundingBox.
  16004.          min _ min min: b origin.
  16005.          max _ max max: b corner].
  16006.     enclosingRect _ ((min - (6@6)) corner: (max + (6@6))) rounded.
  16007.     "update scrolling range"
  16008.     self scrollOffset: scrollOffset.!
  16009. mouseOffset
  16010.     "Answer the offset to convert between window coordinates and logical coordinates."
  16011.  
  16012.     ^scrollOffset - enclosingRect origin!
  16013. viewOrigin
  16014.     "Answer the origin of the view's coordinate system relative to 0@0."
  16015.  
  16016.     ^(0@0) - enclosingRect origin! !
  16017.  
  16018. !MacDrawDemoView methodsFor: 'controller access'!
  16019. defaultControllerClass
  16020.     ^MacDrawDemoController! !
  16021.  
  16022. Smalltalk condenseChanges.!
  16023.  
  16024. '----SNAPSHOT----'!
  16025.  
  16026. "Minstrel.im created at (28 June 1991 10:32:27 pm )"!
  16027.  
  16028. 'From Smalltalk-80, Version 2.3 of 13 June 1988 on 24 June 1991 at 9:04:07 am'!
  16029.  
  16030. StandardSystemView subclass: #ButtonSystemView
  16031.     instanceVariableNames: 'activeEmphasis actionEmphasis '
  16032.     classVariableNames: 'CornerForms '
  16033.     poolDictionaries: ''
  16034.     category: 'Interface-Buttons'!
  16035.  
  16036. !ButtonSystemView methodsFor: 'initialize-release'!
  16037. adjustMinimumSize
  16038.     self minimumSize: model name asParagraph boundingBox extent + (6 @ 6).! !
  16039.  
  16040. !ButtonSystemView methodsFor: 'initialize-release'!
  16041. initialize
  16042.     super initialize.
  16043.     activeEmphasis _ false.
  16044.     actionEmphasis _ false.
  16045.     self label: nil.
  16046.     self borderWidth: 2! !
  16047.  
  16048. !ButtonSystemView methodsFor: 'controller access'!
  16049. collapse
  16050.     self isCollapsed
  16051.         ifFalse: 
  16052.             [self label: model name.
  16053.             super collapse]! !
  16054.  
  16055. !ButtonSystemView methodsFor: 'controller access'!
  16056. defaultControllerClass
  16057.     ^ButtonSystemController! !
  16058.  
  16059. !ButtonSystemView methodsFor: 'controller access'!
  16060. expand
  16061.     self isCollapsed
  16062.         ifTrue: 
  16063.             [self label: nil.
  16064.             super expand]! !
  16065.  
  16066. !ButtonSystemView methodsFor: 'displaying'!
  16067. displayView
  16068.     | name box f g |
  16069.     self isCollapsed ifTrue: [^self].
  16070.     box _ self insetDisplayBox.
  16071.     name _ model name asParagraph.
  16072.     name displayOn: Display at: box topLeft + (1 @ 1).
  16073.     (CornerForms at: 1)
  16074.         displayOn: Display
  16075.         at: box topLeft
  16076.         clippingBox: box
  16077.         rule: Form under
  16078.         mask: Form black.
  16079.     (CornerForms at: 2)
  16080.         displayOn: Display
  16081.         at: box topRight
  16082.         clippingBox: box
  16083.         rule: Form under
  16084.         mask: Form black.
  16085.     (CornerForms at: 3)
  16086.         displayOn: Display
  16087.         at: box bottomRight
  16088.         clippingBox: box
  16089.         rule: Form under
  16090.         mask: Form black.
  16091.     (CornerForms at: 4)
  16092.         displayOn: Display
  16093.         at: box bottomLeft
  16094.         clippingBox: box
  16095.         rule: Form under
  16096.         mask: Form black.
  16097.     actionEmphasis _ activeEmphasis _ false! !
  16098.  
  16099. !ButtonSystemView methodsFor: 'deEmphasizing'!
  16100. actionDeEmphasizeView
  16101.     self isCollapsed
  16102.         ifFalse: 
  16103.             [borderColor _ Form black.
  16104.             insideColor _ nil.
  16105.             actionEmphasis _ false.
  16106.             self displayBorder.
  16107.             insideColor _ Form white]! !
  16108.  
  16109. !ButtonSystemView methodsFor: 'deEmphasizing'!
  16110. actionEmphasizeView
  16111.     self isCollapsed
  16112.         ifFalse: 
  16113.             [borderColor _ Form white.
  16114.             insideColor _ nil.
  16115.             actionEmphasis _ true.
  16116.             self displayBorder.
  16117.             borderColor _ Form black.
  16118.             insideColor _ Form white]! !
  16119.  
  16120. !ButtonSystemView methodsFor: 'deEmphasizing'!
  16121. deEmphasizeView
  16122.     self isCollapsed ifFalse: [activeEmphasis
  16123.             ifTrue: 
  16124.                 [actionEmphasis ifTrue: [self actionDeEmphasizeView].
  16125.                 activeEmphasis _ actionEmphasis _ false.
  16126.                 Display reverse: self insetDisplayBox]]! !
  16127.  
  16128. !ButtonSystemView methodsFor: 'deEmphasizing'!
  16129. emphasizeView
  16130.     self isCollapsed ifFalse: [activeEmphasis not
  16131.             ifTrue: 
  16132.                 [activeEmphasis _ true.
  16133.                 Display reverse: self insetDisplayBox]]! !
  16134.  
  16135. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  16136.  
  16137. ButtonSystemView class
  16138.     instanceVariableNames: ''!
  16139.  
  16140. !ButtonSystemView class methodsFor: 'class initialization'!
  16141. initialize
  16142.     "ButtonSystemView initialize."
  16143.  
  16144.     | f |
  16145.     CornerForms _ Array new: 4.
  16146.     CornerForms at: 1 put: (Form
  16147.             extent: 8 @ 4
  16148.             fromArray: #(65280 63488 49152 32768 )
  16149.             offset: 0 @ 0).
  16150.     CornerForms at: 2 put: ((CornerForms at: 1) reflect: 1 @ 0).
  16151.     (f _ CornerForms at: 2) offset: f width negated @ 0.
  16152.     CornerForms at: 3 put: ((CornerForms at: 2) reflect: 0 @ 1).
  16153.     (f _ CornerForms at: 3) offset: f extent negated.
  16154.     CornerForms at: 4 put: ((CornerForms at: 1) reflect: 0 @ 1).
  16155.     (f _ CornerForms at: 4) offset: 0 @ f height negated! !
  16156.  
  16157. !Point methodsFor: 'arithmetic'!
  16158. negated
  16159.     ^x negated @ y negated! !
  16160.  
  16161. 'Point Smalltalk-80, Version 2.3 of 13 June 1988 on 24 June 1991 at 9:04:07 am'!
  16162.  
  16163. StandardSystemView subclass: #ButtonSystemView
  16164.     instanceVariableNames: 'activeEmphasis actionEmphasis '
  16165.     classVariableNames: 'CornerForms '
  16166.     poolDictionaries: ''
  16167.     category: 'Interface-Buttons'!
  16168.  
  16169. !ButtonSystemView methodsFor: 'initialize-release'!
  16170. adjustMinimumSize
  16171.     self minimumSize: model name asParagraph boundingBox extent + (6 @ 6).! !
  16172.  
  16173. !ButtonSystemView methodsFor: 'initialize-release'!
  16174. initialize
  16175.     super initialize.
  16176.     activeEmphasis _ false.
  16177.     actionEmphasis _ false.
  16178.     self label: nil.
  16179.     self borderWidth: 2! !
  16180.  
  16181. !ButtonSystemView methodsFor: 'controller access'!
  16182. collapse
  16183.     self isCollapsed
  16184.         ifFalse: 
  16185.             [self label: model name.
  16186.             super collapse]! !
  16187.  
  16188. !ButtonSystemView methodsFor: 'controller access'!
  16189. defaultControllerClass
  16190.     ^ButtonSystemController! !
  16191.  
  16192. !ButtonSystemView methodsFor: 'controller access'!
  16193. expand
  16194.     self isCollapsed
  16195.         ifTrue: 
  16196.             [self label: nil.
  16197.             super expand]! !
  16198.  
  16199. !ButtonSystemView methodsFor: 'displaying'!
  16200. displayView
  16201.     | name box f g |
  16202.     self isCollapsed ifTrue: [^self].
  16203.     box _ self insetDisplayBox.
  16204.     name _ model name asParagraph.
  16205.     name displayOn: Display at: box topLeft + (1 @ 1).
  16206.     (CornerForms at: 1)
  16207.         displayOn: Display
  16208.         at: box topLeft
  16209.         clippingBox: box
  16210.         rule: Form under
  16211.         mask: Form black.
  16212.     (CornerForms at: 2)
  16213.         displayOn: Display
  16214.         at: box topRight
  16215.         clippingBox: box
  16216.         rule: Form under
  16217.         mask: Form black.
  16218.     (CornerForms at: 3)
  16219.         displayOn: Display
  16220.         at: box bottomRight
  16221.         clippingBox: box
  16222.         rule: Form under
  16223.         mask: Form black.
  16224.     (CornerForms at: 4)
  16225.         displayOn: Display
  16226.         at: box bottomLeft
  16227.         clippingBox: box
  16228.         rule: Form under
  16229.         mask: Form black.
  16230.     actionEmphasis _ activeEmphasis _ false! !
  16231.  
  16232. !ButtonSystemView methodsFor: 'deEmphasizing'!
  16233. actionDeEmphasizeView
  16234.     self isCollapsed
  16235.         ifFalse: 
  16236.             [borderColor _ Form black.
  16237.             insideColor _ nil.
  16238.             actionEmphasis _ false.
  16239.             self displayBorder.
  16240.             insideColor _ Form white]! !
  16241.  
  16242. !ButtonSystemView methodsFor: 'deEmphasizing'!
  16243. actionEmphasizeView
  16244.     self isCollapsed
  16245.         ifFalse: 
  16246.             [borderColor _ Form white.
  16247.             insideColor _ nil.
  16248.             actionEmphasis _ true.
  16249.             self displayBorder.
  16250.             borderColor _ Form black.
  16251.             insideColor _ Form white]! !
  16252.  
  16253. !ButtonSystemView methodsFor: 'deEmphasizing'!
  16254. deEmphasizeView
  16255.     self isCollapsed ifFalse: [activeEmphasis
  16256.             ifTrue: 
  16257.                 [actionEmphasis ifTrue: [self actionDeEmphasizeView].
  16258.                 activeEmphasis _ actionEmphasis _ false.
  16259.                 Display reverse: self insetDisplayBox]]! !
  16260.  
  16261. !ButtonSystemView methodsFor: 'deEmphasizing'!
  16262. emphasizeView
  16263.     self isCollapsed ifFalse: [activeEmphasis not
  16264.             ifTrue: 
  16265.                 [activeEmphasis _ true.
  16266.                 Display reverse: self insetDisplayBox]]! !
  16267.  
  16268. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  16269.  
  16270. ButtonSystemView class
  16271.     instanceVariableNames: ''!
  16272.  
  16273. !ButtonSystemView class methodsFor: 'class initialization'!
  16274. initialize
  16275.     "ButtonSystemView initialize."
  16276.  
  16277.     | f |
  16278.     CornerForms _ Array new: 4.
  16279.     CornerForms at: 1 put: (Form
  16280.             extent: 8 @ 4
  16281.             fromArray: #(65280 63488 49152 32768 )
  16282.             offset: 0 @ 0).
  16283.     CornerForms at: 2 put: ((CornerForms at: 1) reflect: 1 @ 0).
  16284.     (f _ CornerForms at: 2) offset: f width negated @ 0.
  16285.     CornerForms at: 3 put: ((CornerForms at: 2) reflect: 0 @ 1).
  16286.     (f _ CornerForms at: 3) offset: f extent negated.
  16287.     CornerForms at: 4 put: ((CornerForms at: 1) reflect: 0 @ 1).
  16288.     (f _ CornerForms at: 4) offset: 0 @ f height negated! !
  16289.  
  16290. ButtonSystemView initialize!
  16291.  
  16292. !ScreenController methodsFor: 'buttons'!
  16293. openButton
  16294.     ButtonAction examples! !
  16295.  
  16296. !Project methodsFor: 'buttons'!
  16297. depth
  16298.     ^projectHolder = self
  16299.         ifTrue: [0]
  16300.         ifFalse: [projectHolder depth + 1]! !
  16301.  
  16302. !Project methodsFor: 'buttons'!
  16303. projectHolder
  16304.     ^projectHolder! !
  16305.  
  16306. StandardSystemController subclass: #ButtonSystemController
  16307.     instanceVariableNames: ''
  16308.     classVariableNames: 'ButtonBlueButtonMenu ButtonBlueButtonMessages ButtonYellowButtonMenu ButtonYellowButtonMessages '
  16309.     poolDictionaries: ''
  16310.     category: 'Interface-Buttons'!
  16311.  
  16312. !ButtonSystemController methodsFor: 'initialize-release'!
  16313. initializeBlueButtonMenu
  16314.     self blueButtonMenu: ButtonBlueButtonMenu blueButtonMessages: ButtonBlueButtonMessages.
  16315.     self yellowButtonMenu: ButtonYellowButtonMenu yellowButtonMessages: ButtonYellowButtonMessages! !
  16316.  
  16317. !ButtonSystemController methodsFor: 'control defaults'!
  16318. isControlWanted
  16319.     "I want control whenever the mouse is within the button boundries.
  16320.     This is slightly different behavior than normal, but becomes natural.
  16321.     Note that this will only be checked when no other controller has
  16322.     control, thus only when all other windows on the screen are
  16323.     deselected."
  16324.  
  16325.     ^self viewHasCursor! !
  16326.  
  16327. !ButtonSystemController methodsFor: 'basic control sequence'!
  16328. blueButtonActivity
  16329.     "First mutate the blue button menu so that 'move' will   
  16330.     be under the mouse.  Then do the usual stuff (super)."
  16331.  
  16332.     | moveItem |
  16333.     moveItem _ ButtonBlueButtonMessages indexOf: #move.
  16334.     moveItem = 0 ifFalse: [ButtonBlueButtonMenu setMarkerAt: moveItem].
  16335.     ^super blueButtonActivity! !
  16336.  
  16337. !ButtonSystemController methodsFor: 'basic control sequence'!
  16338. redButtonActivity
  16339.     "The button has been pressed.  First I highlight myself to show that 
  16340.     something is happening.  Then I do the action.  Then I unhighlight 
  16341.     myself (I'm done).  Then I wait for the slow user to release the 
  16342.     button so that I don't auto-repeat.  Then, unless the mouse is still 
  16343.     within the button, I check for a new control to activate.  (This is very 
  16344.     convenient once you get used to it.)"
  16345.  
  16346.     view actionEmphasizeView.
  16347.     model doAction.
  16348.     view actionDeEmphasizeView.
  16349.     [sensor redButtonPressed] whileTrue.
  16350.     self isControlWanted
  16351.         ifFalse: 
  16352.             [self controlTerminate.
  16353.             ScheduledControllers searchForActiveController]! !
  16354.  
  16355. !ButtonSystemController methodsFor: 'scheduling'!
  16356. open
  16357.     view window: view window viewport: (sensor cursorPoint extent: view minimumSize).
  16358.     status _ #open.
  16359.     self moveOpened.
  16360.     ScheduledControllers scheduleActive: self! !
  16361.  
  16362. !ButtonSystemController methodsFor: 'menu messages'!
  16363. changeAction
  16364.     | newAction result |
  16365.     newAction _ FillInTheBlank request: 'New action?' initialAnswer: ''.
  16366.     newAction = '' ifTrue: [^nil].
  16367.     result _ model actionBlockFromString: newAction.
  16368.     model actionBlock: result! !
  16369.  
  16370. !ButtonSystemController methodsFor: 'menu messages'!
  16371. changeName
  16372.     | newName | 
  16373.     newName _ FillInTheBlank request: 'New name?' initialAnswer: model name. 
  16374.     newName = '' ifTrue: [^nil].
  16375.     self setName: newName! !
  16376.  
  16377. !ButtonSystemController methodsFor: 'menu messages'!
  16378. cloneButton
  16379.     | button |
  16380.     button _ model copy.
  16381.     button open! !
  16382.  
  16383. !ButtonSystemController methodsFor: 'menu messages'!
  16384. editButton
  16385.     ButtonBrowser new openOn: self! !
  16386.  
  16387. !ButtonSystemController methodsFor: 'menu messages'!
  16388. inspectButton
  16389.     model inspect! !
  16390.  
  16391. !ButtonSystemController methodsFor: 'model access'!
  16392. getArgumentNames
  16393.     ^model argumentNames! !
  16394.  
  16395. !ButtonSystemController methodsFor: 'model access'!
  16396. getArguments
  16397.     ^model arguments! !
  16398.  
  16399. !ButtonSystemController methodsFor: 'model access'!
  16400. getCodeString
  16401.     ^model codeString! !
  16402.  
  16403. !ButtonSystemController methodsFor: 'model access'!
  16404. getName
  16405.     "Return the name of the button."
  16406.  
  16407.     ^model name! !
  16408.  
  16409. !ButtonSystemController methodsFor: 'model access'!
  16410. getTemporaries
  16411.     ^model temporaries! !
  16412.  
  16413. !ButtonSystemController methodsFor: 'model access'!
  16414. setCodeString: aString temporaries: tnames objects: objects objectNames: onames 
  16415.     ^model
  16416.         setCodeString: aString
  16417.         temporaries: tnames
  16418.         objects: objects
  16419.         objectNames: onames! !
  16420.  
  16421. !ButtonSystemController methodsFor: 'model access'!
  16422. setName: name 
  16423.     "Change the name of the button.  If necessary, resize and  
  16424.     redisplay the button so that the name fits."
  16425.  
  16426.     name = '' ifTrue: [^self].
  16427.     model name: name.
  16428.     self flushDisplayBits.
  16429.     view
  16430.         displaySafe: 
  16431.             [view deEmphasizeView.
  16432.             view erase.
  16433.             view adjustMinimumSize.
  16434.             view window: view window viewport: (view viewport topLeft extent: view minimumSize).
  16435.             view display.
  16436.             view emphasizeView]! !
  16437.  
  16438. !ButtonSystemController methodsFor: 'old methods'!
  16439. old.dragOpened
  16440.     "Just like moveOpened except with the button down."
  16441.  
  16442.     | form frame location background offset |
  16443.     frame _ view displayBox.
  16444.     form _ Form extent: (view labelDisplayBox extent).
  16445.     offset _ (0@form extent y).
  16446.     location _ view labelDisplayBox origin.
  16447.     background _ form backgroundAt: location.
  16448.     form _ view labelForm.
  16449.     form displayAt: location.
  16450.     sensor cursorPoint: location + offset.
  16451.     Cursor origin
  16452.         showWhile:
  16453.             [Display
  16454.                 outline: [frame _ (frame moveTo: sensor cursorPoint) rounded]
  16455.                 do: [form moveTo: frame origin - offset restoring: background]
  16456.                 while: [ sensor anyButtonPressed]
  16457.                 width: 2
  16458.                 halftone: Form gray.
  16459.             background display].
  16460.     view window: view window viewport: frame! !
  16461.  
  16462. !ButtonSystemController methodsFor: 'old methods'!
  16463. old.yellowButtonActivity
  16464.     view isCollapsed ifTrue: [^self].
  16465.     view erase.
  16466.     self dragOpened.
  16467.     view displayEmphasized! !
  16468.  
  16469. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  16470.  
  16471. ButtonSystemController class
  16472.     instanceVariableNames: ''!
  16473.  
  16474. !ButtonSystemController class methodsFor: 'class initialization'!
  16475. initialize
  16476.     "ButtonSystemController initialize."
  16477.  
  16478.     ButtonBlueButtonMenu _ PopUpMenu labels: 'clone\ new name \ new action \under\move\frame\close' withCRs lines: #(3 6 ).
  16479.     ButtonBlueButtonMessages _ #(cloneButton changeName changeAction under move frame close ).
  16480.     ButtonYellowButtonMenu _ PopUpMenu labels: ' clone \edit' withCRs lines: #().
  16481.     ButtonYellowButtonMessages _ #(cloneButton editButton )! !
  16482.  
  16483. ButtonSystemController initialize!
  16484.  
  16485. !Point methodsFor: 'arithmetic'!
  16486. negated
  16487.     ^x negated @ y negated! !
  16488.  
  16489. Model subclass: #ButtonAction
  16490.     instanceVariableNames: 'name block arguments argumentNames temporaryNames codeString '
  16491.     classVariableNames: ''
  16492.     poolDictionaries: ''
  16493.     category: 'Interface-Buttons'!
  16494.  
  16495. !ButtonAction methodsFor: 'initialization'!
  16496. initialize
  16497.     name _ 'Empty Button'.
  16498.     block _ [self dependents do: [:each | (each isKindOf: ButtonSystemView)
  16499.                     ifTrue: [ButtonBrowser new openOn: each controller]]].
  16500.     argumentNames _ #().
  16501.     arguments _ #().
  16502.     temporaryNames _ #().
  16503.     codeString _ ''! !
  16504.  
  16505. !ButtonAction methodsFor: 'scheduling'!
  16506. open
  16507.     | topView |
  16508.     topView _ ButtonSystemView new.
  16509.     topView model: self.
  16510.     topView adjustMinimumSize.
  16511.     topView controller open! !
  16512.  
  16513. !ButtonAction methodsFor: 'access'!
  16514. argumentNames
  16515.     ^argumentNames! !
  16516.  
  16517. !ButtonAction methodsFor: 'access'!
  16518. arguments
  16519.     ^arguments! !
  16520.  
  16521. !ButtonAction methodsFor: 'access'!
  16522. arguments: a
  16523.     arguments _ a! !
  16524.  
  16525. !ButtonAction methodsFor: 'access'!
  16526. codeString
  16527.     ^codeString! !
  16528.  
  16529. !ButtonAction methodsFor: 'access'!
  16530. doAction
  16531.     (block isMemberOf: BlockContext)
  16532.         ifFalse: [self notYetImplemented].
  16533.     block valueWithArguments: arguments.
  16534.     1 to: temporaryNames size do: [:idx | block home tempAt: idx put: nil]! !
  16535.  
  16536. !ButtonAction methodsFor: 'access'!
  16537. name
  16538.     ^name! !
  16539.  
  16540. !ButtonAction methodsFor: 'access'!
  16541. name: aString
  16542.     name _ aString! !
  16543.  
  16544. !ButtonAction methodsFor: 'access'!
  16545. temporaries
  16546.     ^temporaryNames! !
  16547.  
  16548. !ButtonAction methodsFor: 'parsing'!
  16549. setCodeString: aString
  16550.     ^self
  16551.         setCodeString: aString
  16552.         temporaries: #()
  16553.         objects: #()
  16554.         objectNames: #()! !
  16555.  
  16556. !ButtonAction methodsFor: 'parsing'!
  16557. setCodeString: aString objects: objects objectNames: onames
  16558.     ^self
  16559.         setCodeString: aString
  16560.         temporaries: #()
  16561.         objects: objects
  16562.         objectNames: onames! !
  16563.  
  16564. !ButtonAction methodsFor: 'parsing'!
  16565. setCodeString: aString temporaries: tnames objects: objects objectNames: onames 
  16566.     "tnames is an array of temporary variable names.   
  16567.     onames is an array of variable names, each of which references   
  16568.     an object in objects."
  16569.  
  16570.     | methodStream methodNode methodContext |
  16571.     objects size ~= onames size ifTrue: [^self notYetImplemented].
  16572.     codeString _ aString.
  16573.     methodStream _ String new writeStream.
  16574.     methodStream nextPutAll: 'button | '.
  16575.     tnames do: [:each | methodStream nextPutAll: each; space].
  16576.     methodStream nextPutAll: '| ^['.
  16577.     onames do: [:each | methodStream nextPut: $:; nextPutAll: each; space].
  16578.     onames isEmpty ifFalse: [methodStream nextPut: $|].
  16579.     methodStream nextPutAll: aString; nextPut: $].
  16580.     methodNode _ self class compilerClass new
  16581.                 compile: methodStream contents
  16582.                 in: self class
  16583.                 notifying: nil
  16584.                 ifFail: [^self notYetImplemented].
  16585.     self class addSelector: #ButtonIt withMethod: methodNode generate.
  16586.     block _ self ButtonIt.
  16587.     self class removeSelectorSimply: #ButtonIt.
  16588.     block fixTemps.
  16589.     methodContext _ block home.
  16590.     temporaryNames _ tnames.
  16591.     argumentNames _ onames.
  16592.     arguments _ objects.
  16593.     ^true! !
  16594.  
  16595. !ButtonAction methodsFor: 'copying'!
  16596. copy
  16597.     | copy |
  16598.     copy _ super copy.
  16599.     copy arguments: arguments copy.
  16600.     ^copy! !
  16601.  
  16602. !ButtonAction methodsFor: 'yet to convert'!
  16603. actionBlock: aBlock
  16604.     ^actionBlock _ aBlock fixTemps! !
  16605.  
  16606. !ButtonAction methodsFor: 'yet to convert'!
  16607. actionBlockFromString: aString
  16608.     | result | 
  16609.     result _ nil class evaluatorClass new
  16610.                 evaluate: '[' , aString , ']'
  16611.                 in: nil
  16612.                 to: nil
  16613.                 notifying: nil
  16614.                 ifFail: [^self notify: 'Error in action'].
  16615.     (result isKindOf: BlockContext)
  16616.         ifFalse: [^self notify: 'Must be a block'].
  16617.     ^result! !
  16618.  
  16619. !ButtonAction methodsFor: 'yet to convert'!
  16620. openName: aName
  16621.     | topView |
  16622.     name _ aName.
  16623.     topView _ ButtonSystemView new.
  16624.     topView model: self.
  16625.     topView adjustMinimumSize.
  16626.     topView controller open! !
  16627.  
  16628. !ButtonAction methodsFor: 'yet to convert'!
  16629. openName: aName action: aBlock 
  16630.     | topView |
  16631.     name _ aName.
  16632.     actionBlock _ aBlock fixTemps.
  16633.     topView _ ButtonSystemView new.
  16634.     topView model: self.
  16635.     topView adjustMinimumSize.
  16636.     topView controller open! !
  16637.  
  16638. !ButtonAction methodsFor: 'yet to convert'!
  16639. openName: aName actionString: aString 
  16640.     | topView |
  16641.     name _ aName.
  16642.     actionBlock _ (self actionBlockFromString: aString) fixTemps.
  16643.     topView _ ButtonSystemView new.
  16644.     topView model: self.
  16645.     topView adjustMinimumSize.
  16646.     topView controller open! !
  16647.  
  16648. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  16649.  
  16650. ButtonAction class
  16651.     instanceVariableNames: ''!
  16652.  
  16653. !ButtonAction class methodsFor: 'examples & instance creation'!
  16654. clearExample
  16655.     "ButtonAction clearExample."
  16656.  
  16657.     (ButtonAction new) setCodeString: 'Transcript clear'; name: 'Clear'; open! !
  16658.  
  16659. !ButtonAction class methodsFor: 'examples & instance creation'!
  16660. create
  16661.     "ButtonAction create."
  16662.  
  16663.     (ButtonAction new) initialize; open! !
  16664.  
  16665. !ButtonAction class methodsFor: 'examples & instance creation'!
  16666. examples
  16667.     "ButtonAction examples."
  16668.  
  16669.     | sel idx | 
  16670.     sel _ #(create clearExample fileOutExample garbageCollectExample jumpToExample).
  16671.     idx _ (PopUpMenu labels: ' -new- \ clear transcript \ fileout changes \ garbage collect \ jump to project ' withCRs) startUp.
  16672.     idx = 0 ifTrue: [^self].
  16673.     self perform: (sel at: idx)! !
  16674.  
  16675. !ButtonAction class methodsFor: 'examples & instance creation'!
  16676. fileOutExample
  16677.     "ButtonAction fileOutExample."
  16678.  
  16679.     | filename str idx |
  16680.     filename _ FillInTheBlank request: 'File name?' initialAnswer: ''.
  16681.     filename = '' ifTrue: [^nil].
  16682.     str _ filename.
  16683.     idx _ filename findLast: [:c | c = $:].
  16684.     idx ~= 0 ifTrue: [str _ filename copyFrom: idx + 1 to: filename size].
  16685.     (str size > 3 and: ['.st' = (str copyFrom: str size - 2 to: str size)])
  16686.         ifTrue: [str _ str copyFrom: 1 to: str size - 3].
  16687.     str _ str size > 1
  16688.                 ifTrue: ['Fileout ' , str]
  16689.                 ifFalse: ['Fileout'].
  16690.     (ButtonAction new)
  16691.         setCodeString: '(FileStream newFileNamed: filename) fileOutChanges'
  16692.         objects: (Array with: filename)
  16693.         objectNames: (Array with: 'filename'); name: str; open! !
  16694.  
  16695. !ButtonAction class methodsFor: 'examples & instance creation'!
  16696. garbageCollectExample
  16697.     "ButtonAction garbageCollectExample."
  16698.  
  16699.     (ButtonAction new) setCodeString: 'Smalltalk garbageCollect'; name: 'Garbage collect'; open! !
  16700.  
  16701. !ButtonAction class methodsFor: 'examples & instance creation'!
  16702. jumpToExample
  16703.     "ButtonAction jumpToExample."
  16704.  
  16705.     | data proj |
  16706.     data _ Project pickFromMenuOfProjects.
  16707.     data isNil ifTrue: [^self].
  16708.     proj _ data at: 2.
  16709.     (ButtonAction new)
  16710.         setCodeString: 'proj enter'
  16711.         objects: (Array with: proj)
  16712.         objectNames: (Array with: 'proj'); name: 'Jump: ' , (data at: 1); open! !
  16713.  
  16714. !Project class methodsFor: 'buttons'!
  16715. listOfProjects
  16716.     "Project listOfProjects."
  16717.  
  16718.     | projects views projectToShortName projectToLongName proj pname nm rootProject longNameToProject sortedNames returnCollec sortedProjects old |
  16719.     old _ Cursor currentCursor.
  16720.     Cursor execute show.
  16721.     projects _ self allInstances.
  16722.     views _ projects collect: [:p | p dependents select: [:view | view isKindOf: ProjectView]].
  16723.     projectToShortName _ Dictionary new.
  16724.     rootProject _ nil.
  16725.     projects with: views do: [:p :v | projectToShortName at: p put: (v isEmpty
  16726.                 ifTrue: [p projectHolder = p
  16727.                         ifTrue: 
  16728.                             [rootProject _ p.
  16729.                             '']
  16730.                         ifFalse: ['*garbage*']]
  16731.                 ifFalse: [v first topView label])].
  16732.     projectToLongName _ Dictionary new.
  16733.     projectToShortName associationsDo: [:assoc | projectToLongName at: assoc key put: assoc value].
  16734.     1 to: projectToShortName size do: [:i | projectToShortName
  16735.             associationsDo: 
  16736.                 [:assoc | 
  16737.                 proj _ assoc key.
  16738.                 nm _ assoc value.
  16739.                 pname _ projectToLongName at: proj projectHolder.
  16740.                 pname isEmpty ifFalse: [nm _ pname , '/' , nm].
  16741.                 projectToLongName at: proj put: nm]].
  16742.     projectToLongName at: rootProject put: '-root-'.
  16743.     longNameToProject _ Dictionary new.
  16744.     sortedNames _ SortedCollection new.
  16745.     projectToLongName
  16746.         associationsDo: 
  16747.             [:assoc | 
  16748.             longNameToProject at: assoc value put: assoc key.
  16749.             sortedNames add: assoc value].
  16750.     sortedProjects _ OrderedCollection new.
  16751.     sortedNames do: [:nm | sortedProjects addLast: (longNameToProject at: nm)].
  16752.     returnCollec _ OrderedCollection new.
  16753.     returnCollec add: (Array
  16754.             with: (projectToLongName at: rootProject)
  16755.             with: (projectToLongName at: rootProject)
  16756.             with: rootProject).
  16757.     self
  16758.         subList: sortedProjects
  16759.         long: projectToLongName
  16760.         short: projectToShortName
  16761.         parent: rootProject
  16762.         depth: 1
  16763.         into: returnCollec.
  16764.     old show.
  16765.     ^returnCollec! !
  16766.  
  16767. !Project class methodsFor: 'buttons'!
  16768. pickFromMenuOfProjects
  16769.     "Project pickFromMenuOfProjects."
  16770.  
  16771.     | list labels menu idx |
  16772.     list _ Project listOfProjects asArray.
  16773.     labels _ OrderedCollection new.
  16774.     list do: [:each | labels addLast: (each at: 1)].
  16775.     labels _ Array with: labels asArray.
  16776.     menu _ LeftPopUpMenu labelList: labels.
  16777.     idx _ menu startUp: #anyButton at: Sensor cursorPoint - menu center.
  16778.     idx = 0 ifTrue: [^nil].
  16779.     ^Array with: ((list at: idx) at: 2) with: ((list at: idx) at: 3)! !
  16780.  
  16781. !Project class methodsFor: 'buttons'!
  16782. subList: sortedProjects long: projectToLongName short: projectToShortName parent: parent depth: depth into: returnCollec 
  16783.     | str |
  16784.     str _ String new: (depth * 2) withAll: Character space.
  16785.     sortedProjects do: [:proj | (proj depth = depth and: [proj projectHolder = parent])
  16786.             ifTrue: 
  16787.                 [returnCollec add: (Array
  16788.                         with: str , (projectToShortName at: proj)
  16789.                         with: (projectToLongName at: proj)
  16790.                         with: proj).
  16791.                 self
  16792.                     subList: sortedProjects
  16793.                     long: projectToLongName
  16794.                     short: projectToShortName
  16795.                     parent: proj
  16796.                     depth: depth + 1
  16797.                     into: returnCollec]]! !
  16798.  
  16799. !PopUpMenu methodsFor: 'accessing'!
  16800. setMarkerAt: aNumber 
  16801.     "Set the marker to the label to aNumber.  If aNumber is out-of-range 
  16802.     then do nothing."
  16803.  
  16804.     | height y moveItem |
  16805.     aNumber <= 0 ifTrue: [^nil].
  16806.     height _ font height.
  16807.     y _ frame top + (aNumber - 1 * height) + 1.
  16808.     marker _ marker left @ y corner: marker right @ (y + height)! !
  16809.  
  16810. Model subclass: #ButtonBrowser
  16811.     instanceVariableNames: 'theButtonController temporaryList currentTemporary objectNameList objectList currentObjectName '
  16812.     classVariableNames: 'CodeMenu NameMenu ObjectMenu ObjectNameMenus TemporaryMenus '
  16813.     poolDictionaries: ''
  16814.     category: 'Interface-Buttons'!
  16815.  
  16816. !ButtonBrowser methodsFor: 'instance creation'!
  16817. openOn: aButtonController
  16818.     | topView textView listView |
  16819.     theButtonController _ aButtonController.
  16820.     temporaryList _ theButtonController getTemporaries.
  16821.     objectNameList _ theButtonController getArgumentNames.
  16822.     objectList _ theButtonController getArguments.
  16823.     topView _ StandardSystemView
  16824.                 model: self
  16825.                 label: 'Button Browser'
  16826.                 minimumSize: 250 @ 300.
  16827.     textView _ CodeView
  16828.                 on: self
  16829.                 aspect: #name
  16830.                 change: #acceptName:from:
  16831.                 menu: #nameMenu
  16832.                 initialSelection: nil.
  16833.     topView
  16834.         addSubView: textView
  16835.         in: (0 @ 0 extent: 1 @ 0.1)
  16836.         borderWidth: 1.
  16837.     listView _ SelectionInListView
  16838.                 on: self
  16839.                 printItems: false
  16840.                 oneItem: false
  16841.                 aspect: #temporary
  16842.                 change: #temporary:
  16843.                 list: #temporaryList
  16844.                 menu: #temporaryListMenu
  16845.                 initialSelection: #temporary.
  16846.     topView
  16847.         addSubView: listView
  16848.         in: (0 @ 0.1 extent: 0.3 @ 0.4)
  16849.         borderWidth: 1.
  16850.     listView _ SelectionInListView
  16851.                 on: self
  16852.                 printItems: false
  16853.                 oneItem: false
  16854.                 aspect: #objectName
  16855.                 change: #objectName:
  16856.                 list: #objectNameList
  16857.                 menu: #objectNameListMenu
  16858.                 initialSelection: #objectName.
  16859.     topView
  16860.         addSubView: listView
  16861.         in: (0.3 @ 0.1 extent: 0.3 @ 0.4)
  16862.         borderWidth: 1.
  16863.     textView _ CodeView
  16864.                 on: self
  16865.                 aspect: #object
  16866.                 change: #acceptObject:from:
  16867.                 menu: #objectMenu
  16868.                 initialSelection: nil.
  16869.     topView
  16870.         addSubView: textView
  16871.         in: (0.6 @ 0.1 extent: 0.4 @ 0.4)
  16872.         borderWidth: 1.
  16873.     textView _ CodeView
  16874.                 on: self
  16875.                 aspect: #code
  16876.                 change: #acceptCode:from:
  16877.                 menu: #codeMenu
  16878.                 initialSelection: nil.
  16879.     topView
  16880.         addSubView: textView
  16881.         in: (0 @ 0.5 extent: 1 @ 0.5)
  16882.         borderWidth: 1.
  16883.     topView controller open! !
  16884.  
  16885. !ButtonBrowser methodsFor: 'mvc access'!
  16886. acceptCode: aText from: aController 
  16887.     ^theButtonController
  16888.         setCodeString: aText asString
  16889.         temporaries: temporaryList
  16890.         objects: objectList
  16891.         objectNames: objectNameList! !
  16892.  
  16893. !ButtonBrowser methodsFor: 'mvc access'!
  16894. acceptName: aText from: aController 
  16895.     aController view topView controller controlTerminate.
  16896.     theButtonController setName: aText asString.
  16897.     aController view topView controller controlInitialize.
  16898.     ^true! !
  16899.  
  16900. !ButtonBrowser methodsFor: 'mvc access'!
  16901. acceptObject: aText from: aController 
  16902.     | val |
  16903.     val _ Compiler new
  16904.                 evaluate: aText string
  16905.                 in: nil
  16906.                 to: nil
  16907.                 notifying: aController
  16908.                 ifFail: [^false].
  16909.     objectList at: (objectNameList indexOf: currentObjectName)
  16910.         put: val.
  16911.     self changed: #object.
  16912.     ^true! !
  16913.  
  16914. !ButtonBrowser methodsFor: 'mvc access'!
  16915. code
  16916.     ^theButtonController getCodeString asText! !
  16917.  
  16918. !ButtonBrowser methodsFor: 'mvc access'!
  16919. codeMenu
  16920.     ^CodeMenu! !
  16921.  
  16922. !ButtonBrowser methodsFor: 'mvc access'!
  16923. name
  16924.     ^theButtonController getName asText! !
  16925.  
  16926. !ButtonBrowser methodsFor: 'mvc access'!
  16927. nameMenu
  16928.     ^NameMenu! !
  16929.  
  16930. !ButtonBrowser methodsFor: 'mvc access'!
  16931. object
  16932.     ^currentObjectName isNil
  16933.         ifTrue: ['' asText]
  16934.         ifFalse: [(objectList at: (objectNameList indexOf: currentObjectName)) printString asText]! !
  16935.  
  16936. !ButtonBrowser methodsFor: 'mvc access'!
  16937. objectMenu
  16938.     ^ObjectMenu! !
  16939.  
  16940. !ButtonBrowser methodsFor: 'mvc access'!
  16941. objectName
  16942.     ^currentObjectName! !
  16943.  
  16944. !ButtonBrowser methodsFor: 'mvc access'!
  16945. objectName: n
  16946.     currentObjectName _ n.
  16947.     self changed: #object! !
  16948.  
  16949. !ButtonBrowser methodsFor: 'mvc access'!
  16950. objectNameList
  16951.     ^objectNameList! !
  16952.  
  16953. !ButtonBrowser methodsFor: 'mvc access'!
  16954. objectNameListMenu
  16955.     ^ObjectNameMenus at: (currentObjectName isNil
  16956.             ifTrue: [1]
  16957.             ifFalse: [2])! !
  16958.  
  16959. !ButtonBrowser methodsFor: 'mvc access'!
  16960. temporary
  16961.     ^currentTemporary! !
  16962.  
  16963. !ButtonBrowser methodsFor: 'mvc access'!
  16964. temporary: t
  16965.     ^currentTemporary _ t! !
  16966.  
  16967. !ButtonBrowser methodsFor: 'mvc access'!
  16968. temporaryList
  16969.     ^temporaryList! !
  16970.  
  16971. !ButtonBrowser methodsFor: 'mvc access'!
  16972. temporaryListMenu
  16973.     ^TemporaryMenus at: (currentTemporary isNil
  16974.             ifTrue: [1]
  16975.             ifFalse: [2])! !
  16976.  
  16977. !ButtonBrowser methodsFor: 'mvc functions'!
  16978. addObject
  16979.     | name |
  16980.     name _ FillInTheBlank request: 'Object name?'.
  16981.     name isEmpty ifTrue: [^false].
  16982.     objectNameList _ (objectNameList asOrderedCollection) add: name; asArray.
  16983.     objectList _ (objectList asOrderedCollection) add: nil; asArray.
  16984.     currentObjectName _ name.
  16985.     self changed: #objectName.
  16986.     self changed: #object! !
  16987.  
  16988. !ButtonBrowser methodsFor: 'mvc functions'!
  16989. addTemporary
  16990.     | name | 
  16991.     name _ FillInTheBlank request: 'Temporary name?'.
  16992.     name isEmpty ifTrue: [^false].
  16993.     temporaryList _ (temporaryList asOrderedCollection) add: name; asArray.
  16994.     currentTemporary _ name.
  16995.     self changed: #temporary! !
  16996.  
  16997. !ButtonBrowser methodsFor: 'mvc functions'!
  16998. removeObject
  16999.     | idx |
  17000.     idx _ objectNameList indexOf: currentObjectName.
  17001.     objectList _ (objectList copyFrom: 1 to: idx - 1)
  17002.                 , (objectList copyFrom: idx + 1 to: objectList size).
  17003.     objectNameList _ (objectNameList copyFrom: 1 to: idx - 1)
  17004.                 , (objectNameList copyFrom: idx + 1 to: objectNameList size).
  17005.     currentObjectName _ nil.
  17006.     self changed: #object.
  17007.     self changed: #objectName! !
  17008.  
  17009. !ButtonBrowser methodsFor: 'mvc functions'!
  17010. removeTemporary
  17011.     | idx |
  17012.     idx _ temporaryList indexOf: currentTemporary.
  17013.     temporaryList _ (temporaryList copyFrom: 1 to: idx - 1)
  17014.                 , (temporaryList copyFrom: idx + 1 to: temporaryList size).
  17015.     currentTemporary _ nil.
  17016.     self changed: #temporary! !
  17017.  
  17018. !ButtonBrowser methodsFor: 'mvc functions'!
  17019. renameObject
  17020.     | name |
  17021.     name _ FillInTheBlank request: 'Object name?' initialAnswer: currentObjectName.
  17022.     name isEmpty ifTrue: [^false].
  17023.     objectNameList at: (objectNameList indexOf: currentObjectName)
  17024.         put: name.
  17025.     currentObjectName _ name.
  17026.     self changed: #objectName! !
  17027.  
  17028. !ButtonBrowser methodsFor: 'mvc functions'!
  17029. renameTemporary
  17030.     | name | 
  17031.     name _ FillInTheBlank request: 'Temporary name?' initialAnswer: currentTemporary.
  17032.     name isEmpty ifTrue: [^false].
  17033.     temporaryList at: (temporaryList indexOf: currentTemporary) put: name.
  17034.     currentTemporary _ name.
  17035.     self changed: #temporary! !
  17036.  
  17037. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  17038.  
  17039. ButtonBrowser class
  17040.     instanceVariableNames: ''!
  17041.  
  17042. !ButtonBrowser class methodsFor: 'class initialization'!
  17043. initialize
  17044.     "ButtonBrowser initialize"
  17045.  
  17046.     NameMenu _ nil.
  17047.     ObjectMenu _ nil.
  17048.     CodeMenu _ nil.
  17049.     TemporaryMenus _ Array with: (ActionMenu
  17050.                     labels: 'add temporary' withCRs
  17051.                     lines: #()
  17052.                     selectors: #(addTemporary ))
  17053.                 with: (ActionMenu
  17054.                         labels: 'add temporary\rename\remove' withCRs
  17055.                         lines: #(1 2 )
  17056.                         selectors: #(addTemporary renameTemporary removeTemporary )).
  17057.     ObjectNameMenus _ Array with: (ActionMenu
  17058.                     labels: 'add object' withCRs
  17059.                     lines: #()
  17060.                     selectors: #(addObject ))
  17061.                 with: (ActionMenu
  17062.                         labels: 'add object\rename\remove' withCRs
  17063.                         lines: #(1 2 )
  17064.                         selectors: #(addObject renameObject removeObject )).! !
  17065.  
  17066. ButtonBrowser initialize!
  17067.  
  17068. !Project class methodsFor: 'As yet unclassified'!
  17069. pickFromMenuOfProjects
  17070.     "Project pickFromMenuOfProjects."
  17071.  
  17072.     | list labels menu idx |
  17073.     list _ Project listOfProjects asArray.
  17074.     labels _ OrderedCollection new.
  17075.     list do: [:each | labels addLast: (each at: 1)].
  17076.     labels _ Array with: labels asArray.
  17077.     menu _ PopUpMenu labelList: labels.
  17078.     idx _ menu startUp: #anyButton at: Sensor cursorPoint - menu center.
  17079.     idx = 0 ifTrue: [^nil].
  17080.     ^Array with: ((list at: idx) at: 2) with: ((list at: idx) at: 3)! !
  17081.  
  17082. !Project class methodsFor: 'As yet unclassified'!
  17083. pickFromMenuOfProjects
  17084.     "Project pickFromMenuOfProjects."
  17085.  
  17086.     | list labels menu idx |
  17087.     list _ Project listOfProjects asArray.
  17088.     labels _ OrderedCollection new.
  17089.     list do: [:each | labels addLast: (each at: 1)].
  17090.     labels _ Array with: labels asArray.
  17091.     menu _ PopUpMenu labelList: labels.
  17092.     idx _ menu startUp: #anyButton.
  17093.     idx = 0 ifTrue: [^nil].
  17094.     ^Array with: ((list at: idx) at: 2) with: ((list at: idx) at: 3)! !
  17095.  
  17096. '----SNAPSHOT----'!
  17097.  
  17098. "Minstrel.im created at (28 June 1991 11:03:11 pm )"!
  17099.  
  17100. Smalltalk!
  17101.  
  17102. Smalltalk dependents!
  17103.  
  17104. '----SNAPSHOT----'!
  17105.  
  17106. "Minstrel.im created at (28 June 1991 11:09:53 pm )"!
  17107.  
  17108. '----SNAPSHOT----'!
  17109.  
  17110. "Minstrel.im created at (28 June 1991 11:11:42 pm )"!